<?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=Dgupta10</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=Dgupta10"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Dgupta10"/>
	<updated>2026-04-09T18:51:13Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2018&amp;diff=118114</id>
		<title>CSC/ECE 517 Fall 2018</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2018&amp;diff=118114"/>
		<updated>2018-11-02T20:18:33Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[CSC/ECE 517 Fall 2018- Project E1846. OSS Project Navy: Character Issues]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2018/OSS E1848 Write unit tests for assignment team.rb]]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1839_Review_Requirements_and_Thresholds CSC/ECE 517 Fall 2018 E1839 Review Requirements and Thresholds]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1848_Write_unit_tests_for_assignment_team CSC/ECE 517 Fall 2018 E1848 Write unit tests for assignment_team]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task CSC/ECE 517 Fall 2018 E1835_Refactor_delayed_mailer_and_scheduled_task]&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2018&amp;diff=118113</id>
		<title>CSC/ECE 517 Fall 2018</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2018&amp;diff=118113"/>
		<updated>2018-11-02T20:18:23Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[CSC/ECE 517 Fall 2018- Project E1846. OSS Project Navy: Character Issues]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2018/OSS E1848 Write unit tests for assignment team.rb]]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1839_Review_Requirements_and_Thresholds CSC/ECE 517 Fall 2018 E1839 Review Requirements and Thresholds]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1848_Write_unit_tests_for_assignment_team CSC/ECE 517 Fall 2018 E1848 Write unit tests for assignment_team]&lt;br /&gt;
* [http://wiki.expertiza.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task CSC/ECE 517 Fall 2018 E1835_Refactor_delayed_mailer_and_scheduled_task]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2018/OSS E000 Write unit tests for assignment team.rb]]&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=114784</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=114784"/>
		<updated>2017-12-13T18:33:46Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The Problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:Design Document E1795.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:sso_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We have successfully implemented the following components from the solution architecture.&lt;br /&gt;
* SSO App&lt;br /&gt;
The user will login to the Single Signon App and can ask for keys and enable the APIs for using Peerlogic services. Similarly the admin can approve the keys requested by the user, can view the information of the users and add APIs.&lt;br /&gt;
&lt;br /&gt;
'''Credentials for admin login: '''&lt;br /&gt;
&lt;br /&gt;
email: admin@gmail.com&lt;br /&gt;
&lt;br /&gt;
password: admin&lt;br /&gt;
&lt;br /&gt;
Please do not change the password of the admin so that another user doesn't get blocked while testing.&lt;br /&gt;
&lt;br /&gt;
* SSO REST APIs&lt;br /&gt;
Once the key is approved by the admin, the Apps which use the Peerlogic service will use this keys to communicate with the REST Endpoints. A token will be generated from this which will be used by Peerlogic to authenticate and authorize the app. &lt;br /&gt;
&lt;br /&gt;
=&amp;gt; To get the token: (Called by the app)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
URL : https://evening-refuge-64130.herokuapp.com/token/get?clientkey=y4E1irXZQfxVipxKo4llTnc5gdZtzP6OV3xfkS/ZP4U=&lt;br /&gt;
&lt;br /&gt;
Method: GET&lt;br /&gt;
&lt;br /&gt;
Response:&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;client_id&amp;quot;: &amp;quot;someID&amp;quot;,&lt;br /&gt;
    &amp;quot;token&amp;quot;: &amp;quot;someToken&amp;quot;,&lt;br /&gt;
    &amp;quot;message&amp;quot;: &amp;quot;OK&amp;quot;,&lt;br /&gt;
    &amp;quot;status&amp;quot;: 200&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; To authenticate and authorize: (Called by Peerlogic)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
URL : https://evening-refuge-64130.herokuapp.com/token/validate&lt;br /&gt;
&lt;br /&gt;
Method: POST&lt;br /&gt;
&lt;br /&gt;
Payload:&lt;br /&gt;
{&lt;br /&gt;
     &amp;quot;token&amp;quot;: &amp;quot;someToken&amp;quot;, &lt;br /&gt;
     &amp;quot;api&amp;quot;: &amp;quot;Rainbow API&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Response:&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;status&amp;quot;: 200,&lt;br /&gt;
    &amp;quot;message&amp;quot;: &amp;quot;OK&amp;quot;,&lt;br /&gt;
    &amp;quot;clientname&amp;quot;: &amp;quot;App&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In cases where authentication fails, status will come as 401 with appropriate message giving the reason for failure. &lt;br /&gt;
&lt;br /&gt;
* Demo App&lt;br /&gt;
&lt;br /&gt;
We have made a Demo App to show how the API calls to Peerlogic work and token validation.&lt;br /&gt;
** A token is generated when you click on the 'RequestToken'. This token will be sent in the header of the request to Peerlogic while making an API call.&lt;br /&gt;
** Peerlogic verifies this token with SSO.&lt;br /&gt;
** Clicking on 'GetRainbowURL' generates a URL for that service through which we can access it.&lt;br /&gt;
** 'getGraph' shows the visual graph of Rainbow Service.&lt;br /&gt;
** Changing anything in the token will make it an invalid one and the service wouldn't be accessible. An error output will be displayed. &lt;br /&gt;
&lt;br /&gt;
[[File:app.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Test plan ==&lt;br /&gt;
&lt;br /&gt;
To test the app, follow the steps listed below:&lt;br /&gt;
&lt;br /&gt;
1. Go to the single sign on app, login.&lt;br /&gt;
&lt;br /&gt;
2. Create a new app, and request the client key for that.&lt;br /&gt;
&lt;br /&gt;
3. Wait for admin approval. &lt;br /&gt;
&lt;br /&gt;
4. If you have the admin credentials, login as admin, go to clients page, and approve the request you just generated.&lt;br /&gt;
&lt;br /&gt;
5. Once the approval is done, copy the client key and keep it somewhere safe.&lt;br /&gt;
&lt;br /&gt;
6. Now, to access the rainbow graph API, send a request to the SSO for token along with client key.&lt;br /&gt;
&lt;br /&gt;
7. After the token is sent to you, you can use the token as Authorization header in the Rainbow graph API.&lt;br /&gt;
&lt;br /&gt;
8. If the token is correct, you should be able to access the API, else an error will be thrown for unauthorized access.&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=114783</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=114783"/>
		<updated>2017-12-13T18:28:30Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The Problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:Design Document E1795.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:sso_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
We have successfully implemented the following components from the solution architecture.&lt;br /&gt;
* SSO App&lt;br /&gt;
The user will login to the Single Signon App and can ask for keys and enable the APIs for using Peerlogic services. Similarly the admin can approve the keys requested by the user, can view the information of the users and add APIs.&lt;br /&gt;
&lt;br /&gt;
'''Credentials for admin login: '''&lt;br /&gt;
&lt;br /&gt;
email: admin@gmail.com&lt;br /&gt;
&lt;br /&gt;
password: admin&lt;br /&gt;
&lt;br /&gt;
Please do not change the password of the admin so that another user doesn't get blocked while testing.&lt;br /&gt;
&lt;br /&gt;
* SSO REST APIs&lt;br /&gt;
Once the key is approved by the admin, the Apps which use the Peerlogic service will use this keys to communicate with the REST Endpoints. A token will be generated from this which will be used by Peerlogic to authenticate and authorize the app. &lt;br /&gt;
&lt;br /&gt;
=&amp;gt; To get the token: (Called by the app)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
URL : https://evening-refuge-64130.herokuapp.com/token/get?clientkey=y4E1irXZQfxVipxKo4llTnc5gdZtzP6OV3xfkS/ZP4U=&lt;br /&gt;
&lt;br /&gt;
Method: GET&lt;br /&gt;
&lt;br /&gt;
Response:&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;client_id&amp;quot;: &amp;quot;someID&amp;quot;,&lt;br /&gt;
    &amp;quot;token&amp;quot;: &amp;quot;someToken&amp;quot;,&lt;br /&gt;
    &amp;quot;message&amp;quot;: &amp;quot;OK&amp;quot;,&lt;br /&gt;
    &amp;quot;status&amp;quot;: 200&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; To authenticate and authorize: (Called by Peerlogic)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
URL : https://evening-refuge-64130.herokuapp.com/token/validate&lt;br /&gt;
&lt;br /&gt;
Method: POST&lt;br /&gt;
&lt;br /&gt;
Payload:&lt;br /&gt;
{&lt;br /&gt;
     &amp;quot;token&amp;quot;: &amp;quot;someToken&amp;quot;, &lt;br /&gt;
     &amp;quot;api&amp;quot;: &amp;quot;Rainbow API&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Response:&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;status&amp;quot;: 200,&lt;br /&gt;
    &amp;quot;message&amp;quot;: &amp;quot;OK&amp;quot;,&lt;br /&gt;
    &amp;quot;clientname&amp;quot;: &amp;quot;App&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In cases where authentication fails, status will come as 401 with appropriate message giving the reason for failure. &lt;br /&gt;
&lt;br /&gt;
* Demo App&lt;br /&gt;
&lt;br /&gt;
We have made a Demo App to show how the API calls to Peerlogic work and token validation.&lt;br /&gt;
** A token is generated when you click on the 'RequestToken'. This token will be sent in the header of the request to Peerlogic while making an API call.&lt;br /&gt;
** Peerlogic verifies this token with SSO.&lt;br /&gt;
** Clicking on 'GetRainbowURL' generates a URL for that service through which we can access it.&lt;br /&gt;
** 'getGraph' shows the visual graph of Rainbow Service.&lt;br /&gt;
** Changing anything in the token will make it an invalid one and the service wouldn't be accessible. An error output will be displayed. &lt;br /&gt;
&lt;br /&gt;
[[File:app.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Test plan ==&lt;br /&gt;
&lt;br /&gt;
To test the app, follow the steps listed below:&lt;br /&gt;
&lt;br /&gt;
1. Go to the single sign on app, login.&lt;br /&gt;
&lt;br /&gt;
2. Create a new app, and request the client key for that.&lt;br /&gt;
&lt;br /&gt;
3. Wait for admin approval. (Admin will approve this request)&lt;br /&gt;
&lt;br /&gt;
4. Once the approval is done, copy the client key and keep it somewhere safe.&lt;br /&gt;
&lt;br /&gt;
5. Now, to access the rainbow graph API, send a request to the SSO for token along with client key.&lt;br /&gt;
&lt;br /&gt;
6. After the token is sent to you, you can use the token as Authorization header in the Rainbow graph API.&lt;br /&gt;
&lt;br /&gt;
7. If the token is correct, you should be able to access the API, else an error will be thrown for unauthorized access.&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113416</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113416"/>
		<updated>2017-11-15T02:22:38Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The Problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test plan ==&lt;br /&gt;
&lt;br /&gt;
We will be testing our SSO app both manually and using automation using rspec.&lt;br /&gt;
&lt;br /&gt;
Rspec tests will include:&lt;br /&gt;
1. Request a key, application should redirect to the main page with another listing added, with status as requested.&lt;br /&gt;
&lt;br /&gt;
2. Admin approves a key, application should redirect to the main page with listing's status changed to approved and key generated and shown.&lt;br /&gt;
&lt;br /&gt;
3. Admin declines a key, application should redirect to the main page with listing's status changed to declined.&lt;br /&gt;
&lt;br /&gt;
4. User revokes a key, application should redirect to the main page with listing's status changed to revoked.&lt;br /&gt;
&lt;br /&gt;
5. Clients send request, token is generated.&lt;br /&gt;
&lt;br /&gt;
6. Client sends request with valid token, status sent 200 OK.&lt;br /&gt;
&lt;br /&gt;
7. Client sends request with invalid token, status sent 401 Unauthorized. &lt;br /&gt;
&lt;br /&gt;
There might be more tests added during the course of project development based on the requirement.&lt;br /&gt;
&lt;br /&gt;
Manually we will be checking the entire flow of the application, including creating an account, signing in, requesting the token, approving it, etc.&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113415</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113415"/>
		<updated>2017-11-15T02:22:28Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Class diagram for database in SSO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The Problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Test plan ==&lt;br /&gt;
&lt;br /&gt;
We will be testing our SSO app both manually and using automation using rspec.&lt;br /&gt;
&lt;br /&gt;
Rspec tests will include:&lt;br /&gt;
1. Request a key, application should redirect to the main page with another listing added, with status as requested.&lt;br /&gt;
2. Admin approves a key, application should redirect to the main page with listing's status changed to approved and key generated and shown.&lt;br /&gt;
3. Admin declines a key, application should redirect to the main page with listing's status changed to declined.&lt;br /&gt;
4. User revokes a key, application should redirect to the main page with listing's status changed to revoked.&lt;br /&gt;
5. Clients send request, token is generated.&lt;br /&gt;
6. Client sends request with valid token, status sent 200 OK.&lt;br /&gt;
7. Client sends request with invalid token, status sent 401 Unauthorized. &lt;br /&gt;
&lt;br /&gt;
There might be more tests added during the course of project development based on the requirement.&lt;br /&gt;
&lt;br /&gt;
Manually we will be checking the entire flow of the application, including creating an account, signing in, requesting the token, approving it, etc.&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113382</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113382"/>
		<updated>2017-11-15T01:41:52Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* The problem */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The Problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113227</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113227"/>
		<updated>2017-11-14T13:17:02Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Challenges */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified:&lt;br /&gt;
&lt;br /&gt;
1. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;br /&gt;
&lt;br /&gt;
2. Making sure the database is secure: Since our database is going to store the encryption key and IV, it is of utmost importance that the database is secure and not prone to attacks.&lt;br /&gt;
&lt;br /&gt;
== Future Scope ==&lt;br /&gt;
&lt;br /&gt;
In future we would like to use multiple keys for encryption rather than just one constant key for a lifetime. These multiple keys will have a time to live. This will make the system more secure as now they will be different keys used at different times, so in case a key is leaked or even if it isn't, it won't last for much time, and soon a new key will be in place, bringing the system back to its initial secured position.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113226</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113226"/>
		<updated>2017-11-14T13:12:35Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Diving deeper into the SSO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key. As a proposed solution we will use SecureRandom for this purpose, which is an algorithm to generate a random string. Although it is not optimized for uniqueness, if we are generating a 32 bit key, collision is very less likely to happen. &lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm, one of the safest encryption algorithms, will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified that will be the key points we shall be working on:&lt;br /&gt;
&lt;br /&gt;
1. Generation of token and its authorization/authentication: The process of unique token generation and its verification is the key abstraction. We shall be looking and analysing algorithms that can help us achieve this.&lt;br /&gt;
&lt;br /&gt;
2. Creating a secure database that will be used by SSO: Creating a secure and normalised database to store all the information that SSO shall be using is another challenge.&lt;br /&gt;
&lt;br /&gt;
3. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113225</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113225"/>
		<updated>2017-11-14T13:08:06Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Diving deeper into the SSO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key.&lt;br /&gt;
&lt;br /&gt;
3. AES encryption algorithm will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified that will be the key points we shall be working on:&lt;br /&gt;
&lt;br /&gt;
1. Generation of token and its authorization/authentication: The process of unique token generation and its verification is the key abstraction. We shall be looking and analysing algorithms that can help us achieve this.&lt;br /&gt;
&lt;br /&gt;
2. Creating a secure database that will be used by SSO: Creating a secure and normalised database to store all the information that SSO shall be using is another challenge.&lt;br /&gt;
&lt;br /&gt;
3. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113224</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113224"/>
		<updated>2017-11-14T13:07:51Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Diving deeper into the SSO ==&lt;br /&gt;
&lt;br /&gt;
Looking more deeply at the SSO, here are few key points that specify how we are going to implement the SSO:&lt;br /&gt;
&lt;br /&gt;
1. We will use both google sign in and our own sign in to allow a user to create an account and log in.&lt;br /&gt;
2. We will use a random generator to generate the key for every client once the admin approves the request for the key.&lt;br /&gt;
3. AES encryption algorithm will be used to generate the token for every client. This token will hold information including the client key, access rights and the time the token was generated.&lt;br /&gt;
4. When we decrypt the key, we will check whether we have such a client key in our database and whether they are allowed access to whatever it is that they are requesting. (This constitutes the authentication and the authorization portion)&lt;br /&gt;
5. We shall have a RoR application to handle all of this, and a database (whose model is discussed below).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Class diagram for database in SSO ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified that will be the key points we shall be working on:&lt;br /&gt;
&lt;br /&gt;
1. Generation of token and its authorization/authentication: The process of unique token generation and its verification is the key abstraction. We shall be looking and analysing algorithms that can help us achieve this.&lt;br /&gt;
&lt;br /&gt;
2. Creating a secure database that will be used by SSO: Creating a secure and normalised database to store all the information that SSO shall be using is another challenge.&lt;br /&gt;
&lt;br /&gt;
3. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113223</id>
		<title>CSC/ECE 517 Fall 2017/E1795 Single signon for Peerlogic web services (WS intergration)</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1795_Single_signon_for_Peerlogic_web_services_(WS_intergration)&amp;diff=113223"/>
		<updated>2017-11-14T13:01:15Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Class diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem Statement ==&lt;br /&gt;
Description of the problem statement can be viewed on this [https://docs.google.com/document/d/1WYiXxhYyycp9a3I0GTC-4KFgHrg65Tf27ijJNQvxhmk/edit#heading=h.smsn92ion1nv link].&lt;br /&gt;
&lt;br /&gt;
== PeerLogic ==&lt;br /&gt;
&lt;br /&gt;
To understand the problem statement, let us first understand the terms used in the problem statement:&lt;br /&gt;
&lt;br /&gt;
1. Peerlogic: Peerlogic is a service provider for education peer review systems. The project exposes a number of microservices or web APIs that can be consumed by peer assessment systems. It provides services for reputation algorithms, metareview metrics, etc. To give an example, a peer review system like Expertiza leverages Peerlogic APIs to assess whether a given review was competent enough or not. There are a dozen of such systems that leverage Peerlogic’s APIs for a number of purposes. More details on Peerlogic can be viewed [https://www.peerlogic.org/ here].&lt;br /&gt;
&lt;br /&gt;
2. Expertiza: Expertiza is a peer assessment system that is build to help students review each others work and provide feedback, facilitating learning. Expertiza uses Peerlogic’s services for various purposes.&lt;br /&gt;
&lt;br /&gt;
3. Single Sign On Portal: Single sign on portal is the system that E1795 aims at building. This will serve as an authentication layer between Peerlogic and all other applications using its API.&lt;br /&gt;
&lt;br /&gt;
== The problem ==&lt;br /&gt;
&lt;br /&gt;
Currently Peerlogic’s services can be used by anyone calling them. There is no system to check if an application accessing the services is actually allowed to do so.  It is essential to have a system in place to authorize applications to avoid a number of security breaches that could occur using these open-to-all services and prevent them from being hacked.&lt;br /&gt;
&lt;br /&gt;
== Proposed Solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is to create a “Single Sign On Application” that will be responsible for providing authorization and authentication for the Peerlogic APIs. This application have two major modules:&lt;br /&gt;
&lt;br /&gt;
1. User facing portal: &lt;br /&gt;
The user facing portal will be a deployed application with an user interface that a user/admin can use to register himself, request an API key for his/her app (in case of user), approve API keys (in case of admin), manage keys, and other similar functions.&lt;br /&gt;
&lt;br /&gt;
2. REST APIs for Peerlogic: &lt;br /&gt;
There will be REST API created which Peerlogic can call to check whether a request received by Peerlogic is authorized and authenticated. This API is a core feature because it is responsible for actually putting the security system in place. If the API fails to return the correct result, an application not authorized to access Peerlogic may do so, leading to a security breach.&lt;br /&gt;
&lt;br /&gt;
== Solution Architecture ==&lt;br /&gt;
&lt;br /&gt;
In order to understand how the whole system will work, have a look at the figure given below.&lt;br /&gt;
[[File:peerlogic.jpg]]&lt;br /&gt;
&lt;br /&gt;
The system includes a SSO portal, Peerlogic and different apps trying to access Peerlogic services. The types of users are admin and generic user (who will be responsible for creating a client account with SSO. &lt;br /&gt;
&lt;br /&gt;
Note: In the following description, client has been used interchangeably with app.&lt;br /&gt;
&lt;br /&gt;
1. Once the client users registers himself/the client, and client account is created. He can now request a client ID and a client key to be used by his/her app. (Step 1)&lt;br /&gt;
&lt;br /&gt;
2. SSO sends this request forward to the admin, who either approve/reject this request. The admin tells whether the request is to be approved or not and forwards this information back to peerlogic. (Steps 2 and 3)&lt;br /&gt;
&lt;br /&gt;
3. If the admin, approves the request, SSO generates a client ID and a client token that will be used by the client to send requests to SSO. (Step 4)&lt;br /&gt;
&lt;br /&gt;
4. This client ID and key is seen by the consumer and they add this to the client app. (Steps 5 and 6)&lt;br /&gt;
&lt;br /&gt;
5. When the client app decides it wants to call Peerlogic web services, it communicates with SSO, sending a request for a token, this request includes the client id and client key in order to let know SSO know he is a valid requester for token. (Step 7)&lt;br /&gt;
&lt;br /&gt;
6. SSO generates a unique, one time use token for the client and passes it back to him. (Step 8)&lt;br /&gt;
&lt;br /&gt;
7. The client now calls the Peerlogic web service and adds this token in the request as a header. (Step 9)&lt;br /&gt;
&lt;br /&gt;
8. Peerlogic, after receiving the client request, sends a request to SSO with the token, asking if the token is valid and is allowed access to the service that client is requesting. SSO, at this point, checks does authorization and authentication. If all okay, it returns so. (Steps 10 and 11)&lt;br /&gt;
&lt;br /&gt;
9. If Peerlogic receives a positive response from SSO, it lets client use its API, else returns an unauthorized/unauthenticated access error. (Step 12)&lt;br /&gt;
&lt;br /&gt;
== Class diagram ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the database that will be in work for the SSO application. &lt;br /&gt;
* API will store information about the different APIs and has two attributes: API_id and and the API name. &lt;br /&gt;
* Clients will store information about the clients. It will store which client id has what key. Also the owner of the client will be stored in this table.&lt;br /&gt;
* Access Rights will store information about which client has access to what APIs. This table will be used when we are checking the authorization of a particular client.&lt;br /&gt;
* Users will store information about the users/ The term user here is used to represent the entity which will represent the client. So a user account is nothing but a client facing account.&lt;br /&gt;
* Keys will store the value of the keys used and generated for encryption. Since we are using AES encryption algorithm, we need two values IV and Key. This values will be stored here along with the timestamp when they were generated. Why we have incorporated timestamp is because in future we might like to implement a TTL (Time to live) concept in the generation of token, in which case we can also use different keys for different times.&lt;br /&gt;
&lt;br /&gt;
[[File:class_diagram.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Challenges ==&lt;br /&gt;
&lt;br /&gt;
There are a couple of challenges we have identified that will be the key points we shall be working on:&lt;br /&gt;
&lt;br /&gt;
1. Generation of token and its authorization/authentication: The process of unique token generation and its verification is the key abstraction. We shall be looking and analysing algorithms that can help us achieve this.&lt;br /&gt;
&lt;br /&gt;
2. Creating a secure database that will be used by SSO: Creating a secure and normalised database to store all the information that SSO shall be using is another challenge.&lt;br /&gt;
&lt;br /&gt;
3. Creating a client id and key and storing it: Given the rise of open source software, it is essential that the client id and key that is generated for an app is stored in a secure place, invisible to the world. We will be looking into ways how open source apps do this and good practices to do the same.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111622</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111622"/>
		<updated>2017-11-03T02:12:09Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
==='''action_allowed? method'''===&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
==='''Replaced find_by_map_id with find_by'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
==='''Replacing sorting technique'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring pending_surveys method'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;br /&gt;
&lt;br /&gt;
=='''References'''==&lt;br /&gt;
1. Expertiza Main Repo [https://github.com/expertiza/expertiza]&lt;br /&gt;
&lt;br /&gt;
2. Expertiza Documentation [http://wiki.expertiza.ncsu.edu/index.php/Main_Page]&lt;br /&gt;
&lt;br /&gt;
3. Pull Request [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
4. Screencast for E1745 [https://www.youtube.com/watch?v=VfiPCQmnuAc]&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111621</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111621"/>
		<updated>2017-11-03T02:11:56Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
==='''action_allowed? method'''===&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
==='''Replaced find_by_map_id with find_by'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
==='''Replacing sorting technique'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring pending_surveys method'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;br /&gt;
&lt;br /&gt;
=='''References'''==&lt;br /&gt;
1. Expertiza Main Repo [https://github.com/expertiza/expertiza]&lt;br /&gt;
2. Expertiza Documentation [http://wiki.expertiza.ncsu.edu/index.php/Main_Page]&lt;br /&gt;
3. Pull Request [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
4. Screencast for E1745 [https://www.youtube.com/watch?v=VfiPCQmnuAc]&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111618</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111618"/>
		<updated>2017-11-03T02:07:50Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Refactoring Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
==='''action_allowed? method'''===&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
==='''Replaced find_by_map_id with find_by'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
==='''Replacing sorting technique'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring pending_surveys method'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111617</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111617"/>
		<updated>2017-11-03T02:07:21Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Replaced find_by_map_id with find_by */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
==='''action_allowed? method'''===&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Replaced find_by_map_id with find_by'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
==='''Replacing sorting technique'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring pending_surveys method'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111616</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111616"/>
		<updated>2017-11-03T02:07:08Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Refactoring Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
==='''action_allowed? method'''===&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Replaced find_by_map_id with find_by'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==='''Replacing sorting technique'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring pending_surveys method'''===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111612</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111612"/>
		<updated>2017-11-03T02:05:31Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=='''Introduction'''==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111611</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111611"/>
		<updated>2017-11-03T02:05:20Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* About response_controller.rb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
=='''About response_controller.rb'''==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111610</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111610"/>
		<updated>2017-11-03T02:05:10Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Tasks accomplished */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
=='''Tasks accomplished'''==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111609</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111609"/>
		<updated>2017-11-03T02:04:59Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Refactoring Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
=='''Refactoring Explained'''==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111608</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111608"/>
		<updated>2017-11-03T02:04:44Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test Plan and Execution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=='''Test Plan and Execution'''==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111607</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111607"/>
		<updated>2017-11-03T02:04:31Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* What all was tested */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Test Plan and Execution==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111606</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111606"/>
		<updated>2017-11-03T02:04:09Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* What all was tested */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Test Plan and Execution==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
=What all was tested=&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111605</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111605"/>
		<updated>2017-11-03T02:03:52Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* What all was tested */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Test Plan and Execution==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111603</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111603"/>
		<updated>2017-11-03T02:03:40Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* What all was tested */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Test Plan and Execution==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===''What all was tested''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111602</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111602"/>
		<updated>2017-11-03T02:03:22Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==About response_controller.rb==&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==Tasks accomplished==&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==Refactoring Explained==&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Test Plan and Execution==&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='''What all was tested'''===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='''Stubs and mocks'''===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111600</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111600"/>
		<updated>2017-11-03T02:02:04Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Tasks accomplished */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Writing stubs and mocks&lt;br /&gt;
* Writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
===Stubs and mocks===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111599</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111599"/>
		<updated>2017-11-03T02:01:04Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test Plan and Execution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
===Stubs and mocks===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111598</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111598"/>
		<updated>2017-11-03T02:00:35Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Stubs and mocks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc since we are changing only the implementation of the code. And a general rule of writing test cases is that changing the implementation should not have any effect on tests. Test case scenarios were provided by our mentor and our job was to write the integration tests for those scenarios. the test cases were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
===Stubs and mocks===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;br /&gt;
&lt;br /&gt;
First let us understand how a mock object is created. Have a look at the following piece of code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; let(:review_response) { build(:response, id: 1, map_id: 1) } &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will build a response object (whose specifications are provided in the factories.rb file) with an id 1 and make it available through out the test process. We are therefore using this object as the object returned from a database without actually interacting with the database, thus &amp;quot;mocking&amp;quot; an object.&lt;br /&gt;
&lt;br /&gt;
To understand how stubs work, consider the following piece of code in before(:each) block of the testing controller:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this stub does is that when Response.find is called, instead of going into the database and finding an object and returning it, Rails will blindly return review_response mock. So this line tells Rails that if find is called on Response, return the pre created about review_response. This reduces the dependency on the database.&lt;br /&gt;
&lt;br /&gt;
We wrote stubs and mocks required to successfully test all the pieces of the controller. All of it can be viewed in response_controller_spec.rb.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111338</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111338"/>
		<updated>2017-11-02T19:31:48Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* 'Stubs and mocks' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc and filled out the preexisting test cases present, which were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are either an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
===Stubs and mocks===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111337</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111337"/>
		<updated>2017-11-02T19:31:38Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test Plan and Execution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc and filled out the preexisting test cases present, which were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are either an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='Stubs and mocks'===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111334</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111334"/>
		<updated>2017-11-02T19:31:27Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Test Plan and Execution */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting params = {action: &amp;quot;view&amp;quot;, id: review_response.id}.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc and filled out the preexisting test cases present, which were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are either an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='Stubs and mocks'===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111332</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111332"/>
		<updated>2017-11-02T19:31:04Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* 'What all was tested' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting &amp;lt;pre&amp;gt; params = {action: &amp;quot;view&amp;quot;, id: review_response.id} &amp;lt;/pre&amp;gt;.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
===What all was tested===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc and filled out the preexisting test cases present, which were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are either an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code.&lt;br /&gt;
&lt;br /&gt;
==='Stubs and mocks'===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111330</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=111330"/>
		<updated>2017-11-02T19:30:51Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Integration Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Test Plan and Execution'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
These tests check for the basic functionality of the controller response_controller.rb and whether these function calls redirect to the right place with the correct status code. Consider the following example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when params action is view' do&lt;br /&gt;
      context 'when response_map is a ReviewResponseMap and current user is the instructor of current assignment' do&lt;br /&gt;
        it 'allows certain action' do&lt;br /&gt;
          params = {action: &amp;quot;view&amp;quot;, id: review_response.id}&lt;br /&gt;
          controller.params = params&lt;br /&gt;
          expect(controller.action_allowed?).to eq(true)&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;
The above given test checks that if the instructor wants to view a review, he is given permission to go ahead and view it. This is checked by setting &amp;lt;pre&amp;gt; params = {action: &amp;quot;view&amp;quot;, id: review_response.id} &amp;lt;/pre&amp;gt;.&lt;br /&gt;
To do so, we set these params and expect the function action_allowed to return true.&lt;br /&gt;
The current user is set in the before(:each) part of the test file because that is used commonly by a number of test cases.&lt;br /&gt;
&lt;br /&gt;
==='What all was tested'===&lt;br /&gt;
We tested the existing functionality of the controller like view, edit, action_allowed, redirection, etc and filled out the preexisting test cases present, which were pretty exhaustive. We didn't have to write extra cases for the parts we refactored as the refactored portions are either an extraction of an existing function in smaller ones, in which case the existing function is already calling the new written code. So in a way writing the test cases for existing parts automatically tests the new refactored code. &lt;br /&gt;
&lt;br /&gt;
==='Stubs and mocks'===&lt;br /&gt;
We wrote a number of stubs for the test cases. We separated out stubs into two parts, the ones that are being commonly used by multiple tests and wrote them in the before(:each) part. The other uncommon ones are written in the respective test cases to avoid extra computation. Stubs allowed us to replicate the behaviour of the database without actually calling, thus avoiding cost of accessing the database and avoiding the pitfall of having a test case fail because of an incorrect database layer logic rather than the controller logic.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=110170</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=110170"/>
		<updated>2017-10-27T22:06:56Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Integration Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Integration Tests'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are the stubs and mocks written for the testing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  success_response = Net::HTTPResponse.new(1.0, 200, &amp;quot;OK&amp;quot;)&lt;br /&gt;
  current_round = 1&lt;br /&gt;
  stage = nil&lt;br /&gt;
  let(:assignment) { build(:assignment, instructor_id: 6) }&lt;br /&gt;
  let(:instructor) { build(:instructor, id: 6) }&lt;br /&gt;
  let(:participant) { build(:participant, id: 1, user_id: 6, assignment: assignment) }&lt;br /&gt;
  let(:review_response) { build(:response, id: 1, map_id: 1) }&lt;br /&gt;
  let(:review_response_map) { build(:review_response_map, id: 1, reviewer: participant) }&lt;br /&gt;
  let(:questionnaire) { build(:questionnaire, id: 1, questions: [question]) }&lt;br /&gt;
  let(:question) { Criterion.new(id: 1, weight: 2, break_before: true) }&lt;br /&gt;
  let(:assignment_questionnaire) { build(:assignment_questionnaire) }&lt;br /&gt;
  let(:answer) { double('Answer') }&lt;br /&gt;
  let(:assignment_due_date) { build(:assignment_due_date) }&lt;br /&gt;
&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    stub_current_user(instructor, instructor.role.name, instructor.role)&lt;br /&gt;
    allow(Assignment).to receive(:find).with('1').and_return(assignment)&lt;br /&gt;
    allow(Assignment).to receive(:find).and_return(assignment)&lt;br /&gt;
    allow(Response).to receive(:find).with('1').and_return(review_response)&lt;br /&gt;
    allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
    allow(Response).to receive(:find_by).and_return(review_response)&lt;br /&gt;
    allow(ResponseMap).to receive(:find).with('1').and_return(review_response_map)&lt;br /&gt;
    allow(ResponseMap).to receive(:find).with(1).and_return(review_response_map)&lt;br /&gt;
    allow(Participant).to receive(:find).with(1).and_return(participant)&lt;br /&gt;
    allow(Questionnaire).to receive(:find).with('1').and_return(questionnaire)&lt;br /&gt;
    allow(assignment).to receive(:number_of_current_round).and_return(current_round)&lt;br /&gt;
    allow(assignment).to receive(:get_current_stage).and_return(stage)&lt;br /&gt;
    allow(review_response).to receive(:delete).and_return(success_response)&lt;br /&gt;
    allow(review_response).to receive(:map).and_return(review_response_map)&lt;br /&gt;
    allow(review_response).to receive(:questionnaire_by_answer).and_return(questionnaire)&lt;br /&gt;
    allow(review_response_map).to receive(:assignment).and_return(assignment)&lt;br /&gt;
    allow(review_response_map).to receive(:save).and_return(true)&lt;br /&gt;
    allow(review_response_map).to receive(:questionnaire).with(current_round).and_return(questionnaire)&lt;br /&gt;
    request.env['HTTP_REFERER'] = 'www.google.com'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=110169</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=110169"/>
		<updated>2017-10-27T22:06:41Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Integration Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Integration Tests'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are the stubs and mocks written for the testing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
success_response = Net::HTTPResponse.new(1.0, 200, &amp;quot;OK&amp;quot;)&lt;br /&gt;
  current_round = 1&lt;br /&gt;
  stage = nil&lt;br /&gt;
  let(:assignment) { build(:assignment, instructor_id: 6) }&lt;br /&gt;
  let(:instructor) { build(:instructor, id: 6) }&lt;br /&gt;
  let(:participant) { build(:participant, id: 1, user_id: 6, assignment: assignment) }&lt;br /&gt;
  let(:review_response) { build(:response, id: 1, map_id: 1) }&lt;br /&gt;
  let(:review_response_map) { build(:review_response_map, id: 1, reviewer: participant) }&lt;br /&gt;
  let(:questionnaire) { build(:questionnaire, id: 1, questions: [question]) }&lt;br /&gt;
  let(:question) { Criterion.new(id: 1, weight: 2, break_before: true) }&lt;br /&gt;
  let(:assignment_questionnaire) { build(:assignment_questionnaire) }&lt;br /&gt;
  let(:answer) { double('Answer') }&lt;br /&gt;
  let(:assignment_due_date) { build(:assignment_due_date) }&lt;br /&gt;
&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    stub_current_user(instructor, instructor.role.name, instructor.role)&lt;br /&gt;
    allow(Assignment).to receive(:find).with('1').and_return(assignment)&lt;br /&gt;
    allow(Assignment).to receive(:find).and_return(assignment)&lt;br /&gt;
    allow(Response).to receive(:find).with('1').and_return(review_response)&lt;br /&gt;
    allow(Response).to receive(:find).and_return(review_response)&lt;br /&gt;
    allow(Response).to receive(:find_by).and_return(review_response)&lt;br /&gt;
    allow(ResponseMap).to receive(:find).with('1').and_return(review_response_map)&lt;br /&gt;
    allow(ResponseMap).to receive(:find).with(1).and_return(review_response_map)&lt;br /&gt;
    allow(Participant).to receive(:find).with(1).and_return(participant)&lt;br /&gt;
    allow(Questionnaire).to receive(:find).with('1').and_return(questionnaire)&lt;br /&gt;
    allow(assignment).to receive(:number_of_current_round).and_return(current_round)&lt;br /&gt;
    allow(assignment).to receive(:get_current_stage).and_return(stage)&lt;br /&gt;
    allow(review_response).to receive(:delete).and_return(success_response)&lt;br /&gt;
    allow(review_response).to receive(:map).and_return(review_response_map)&lt;br /&gt;
    allow(review_response).to receive(:questionnaire_by_answer).and_return(questionnaire)&lt;br /&gt;
    allow(review_response_map).to receive(:assignment).and_return(assignment)&lt;br /&gt;
    allow(review_response_map).to receive(:save).and_return(true)&lt;br /&gt;
    allow(review_response_map).to receive(:questionnaire).with(current_round).and_return(questionnaire)&lt;br /&gt;
    request.env['HTTP_REFERER'] = 'www.google.com'&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109347</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109347"/>
		<updated>2017-10-26T03:46:23Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Integration Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Integration Tests'''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109346</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109346"/>
		<updated>2017-10-26T03:45:56Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Pull request'''===&lt;br /&gt;
&lt;br /&gt;
The pull request for this task can be viewed at [https://github.com/expertiza/expertiza/pull/1025]&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109344</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109344"/>
		<updated>2017-10-26T03:42:38Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Tasks done by the team */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks accomplished'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109343</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109343"/>
		<updated>2017-10-26T03:42:19Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Team Members */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks done by the team'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109341</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109341"/>
		<updated>2017-10-26T03:41:53Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* 'Integration Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks done by the team'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Team Members'''===&lt;br /&gt;
1) Pavneet Singh Anand&lt;br /&gt;
&lt;br /&gt;
2) Dipansha Gupta&lt;br /&gt;
&lt;br /&gt;
3) Kshittiz Kumar&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;br /&gt;
Writing the test including writing stubs and mocks to ensure that the tests are fed what is required.&lt;br /&gt;
&lt;br /&gt;
The following are a few test cases written by the team:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#edit' do&lt;br /&gt;
    it 'renders response#response page' do&lt;br /&gt;
      params = {id: review_response.id, return: ''}&lt;br /&gt;
      post :edit, params: params&lt;br /&gt;
      expect(response).to render_template(&amp;quot;response&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '#pending_surveys' do&lt;br /&gt;
    context 'when session[:user] is nil' do&lt;br /&gt;
      it 'redirects to root path (/)' do&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to redirect_to('/')&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when session[:user] is not nil' do&lt;br /&gt;
      it 'renders pending_surveys page' do&lt;br /&gt;
        session[:user] = participant&lt;br /&gt;
        get &amp;quot;pending_surveys&amp;quot;&lt;br /&gt;
        expect(response).to have_http_status(200)&lt;br /&gt;
        expect(response).to render_template(&amp;quot;pending_surveys&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109338</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109338"/>
		<updated>2017-10-26T03:36:54Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: /* Tasks done by the team */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks done by the team'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Team Members'''===&lt;br /&gt;
1) Pavneet Singh Anand&lt;br /&gt;
&lt;br /&gt;
2) Dipansha Gupta&lt;br /&gt;
&lt;br /&gt;
3) Kshittiz Kumar&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109337</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109337"/>
		<updated>2017-10-26T03:36:28Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
Expertiza is an open source webapp built on Ruby on Rails stack. It provides a platform to students with various features like peer-reviewing projects, submitting work, form teams, viewing grades etc. The project is being built and maintained by students and faculty at NCSU.&lt;br /&gt;
&lt;br /&gt;
==='''About response_controller.rb'''===&lt;br /&gt;
The file response_controller.rb handles the operations on responses based on user permissions and redirects the user to the appropriate place after the action is complete. The responses here constitute of peer reviews/questionnaires/survey. The controller takes care of tasks such as creating, saving, editing, updating and deleting these responses.&lt;br /&gt;
&lt;br /&gt;
==='''Tasks done by the team'''===&lt;br /&gt;
1. Refactoring response_controller.rb&lt;br /&gt;
Included:&lt;br /&gt;
* Breaking down large methods into smaller chunks of readable reusable code.&lt;br /&gt;
* Changing code to adhere to latest Ruby conventions&lt;br /&gt;
* Creating functions to reuse chunks of code that were previously written multiple times&lt;br /&gt;
&lt;br /&gt;
2. Testing response_controller.rb&lt;br /&gt;
Included writing integration test cases to ensure that response_controller redirects to the right places with a given parameter set.&lt;br /&gt;
&lt;br /&gt;
==='''Team Members'''===&lt;br /&gt;
1) Pavneet Singh Anand&lt;br /&gt;
&lt;br /&gt;
2) Dipansha Gupta&lt;br /&gt;
&lt;br /&gt;
3) Kshittiz Kumar&lt;br /&gt;
&lt;br /&gt;
==='''Refactoring Explained'''===&lt;br /&gt;
Without wasting much time, lets jump into the refactoring by describing code which existed previously followed by the changed code.&lt;br /&gt;
&lt;br /&gt;
1) action_allowed? method&lt;br /&gt;
&lt;br /&gt;
Previous Code :-&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    case params[:action]&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      map = response.map&lt;br /&gt;
      assignment = response.map.reviewer.assignment&lt;br /&gt;
      # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
      if map.is_a? ReviewResponseMap&lt;br /&gt;
        reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
      else&lt;br /&gt;
        return current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view case is extracted into a separate method and some common variables have been extracted out of the cases &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    response = user_id = nil&lt;br /&gt;
    action = params[:action]&lt;br /&gt;
    if %w(edit delete update view).include?(action)&lt;br /&gt;
      response = Response.find(params[:id])&lt;br /&gt;
      user_id = response.map.reviewer.user_id if (response.map.reviewer)&lt;br /&gt;
    end&lt;br /&gt;
    case action&lt;br /&gt;
    when 'edit' # If response has been submitted, no further editing allowed&lt;br /&gt;
      return false if response.is_submitted&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
      # Deny access to anyone except reviewer &amp;amp; author's team&lt;br /&gt;
    when 'delete', 'update'&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    when 'view'&lt;br /&gt;
      return edit_allowed?(response.map, user_id)&lt;br /&gt;
    else&lt;br /&gt;
      current_user&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def edit_allowed?(map, user_id)&lt;br /&gt;
    assignment = map.reviewer.assignment&lt;br /&gt;
    # if it is a review response map, all the members of reviewee team should be able to view the reponse (can be done from heat map)&lt;br /&gt;
    if map.is_a? ReviewResponseMap&lt;br /&gt;
      reviewee_team = AssignmentTeam.find(map.reviewee_id)&lt;br /&gt;
      return current_user_id?(user_id) || reviewee_team.has_user(current_user) || current_user.role.name == 'Administrator' || (current_user.role.name == 'Instructor' and assignment.instructor_id == current_user.id) || (current_user.role.name == 'Teaching Assistant' and TaMapping.exists?(ta_id: current_user.id, course_id: assignment.course.id))&lt;br /&gt;
    else&lt;br /&gt;
      return current_user_id?(user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This has extracted an independent functionality and enhanced readability apart from sticking to guidelines of short methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Replaced find_by_map_id with find_by&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by_map_id(params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moving on with latest Rails conventions, function is being modified as&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@map = Response.find_by(map_id: params[:id])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will avoid any unexpected behaviour when further upgrading the Rails framework.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Replacing sorting technique&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort {|a, b| a.seq &amp;lt;=&amp;gt; b.seq }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
has been replaced with &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
questions.sort_by(&amp;amp;:seq)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the way to sort based on an object attribute.&lt;br /&gt;
&lt;br /&gt;
4) Refactoring pending_surveys method&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
    course_participants = CourseParticipant.where(user_id: session[:user].id)&lt;br /&gt;
    assignment_participants = AssignmentParticipant.where(user_id: session[:user].id)&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    if course_participants&lt;br /&gt;
      course_participants.each do |cp|&lt;br /&gt;
        survey_deployments = CourseSurveyDeployment.where(parent_id: cp.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; cp.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; cp.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the assignment survey deployments for this user&lt;br /&gt;
    if assignment_participants&lt;br /&gt;
      assignment_participants.each do |ap|&lt;br /&gt;
        survey_deployments = AssignmentSurveyDeployment.where(parent_id: ap.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
          [&lt;br /&gt;
            'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
            'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
            'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
            'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
            'parent_id' =&amp;gt; ap.parent_id,&lt;br /&gt;
            'participant_id' =&amp;gt; ap.id,&lt;br /&gt;
            'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
          ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method involved a lot of code which violates guideline of short methods. Moreover, the lines of code can be reduced along with readability enhanced as similar functionalities in multiple lines can be combined.&lt;br /&gt;
&lt;br /&gt;
53 lines of code have been reduced to 32.&lt;br /&gt;
The refactored method is given below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  def pending_surveys&lt;br /&gt;
    unless session[:user] # Check for a valid user&lt;br /&gt;
      redirect_to '/'&lt;br /&gt;
      return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # Get all the course survey deployments for this user&lt;br /&gt;
    @surveys = []&lt;br /&gt;
    [CourseParticipant, AssignmentParticipant].each do |item|&lt;br /&gt;
      # Get all the participant(course or assignment) entries for this user&lt;br /&gt;
      participant_type = item.where(user_id: session[:user].id)&lt;br /&gt;
      next unless participant_type&lt;br /&gt;
      participant_type.each do |p|&lt;br /&gt;
        survey_deployment_type = participant_type == CourseParticipant ? AssignmentSurveyDeployment : CourseSurveyDeployment&lt;br /&gt;
        survey_deployments = survey_deployment_type.where(parent_id: p.parent_id)&lt;br /&gt;
        next unless survey_deployments&lt;br /&gt;
        survey_deployments.each do |survey_deployment|&lt;br /&gt;
          next unless survey_deployment &amp;amp;&amp;amp; Time.now &amp;gt; survey_deployment.start_date &amp;amp;&amp;amp; Time.now &amp;lt; survey_deployment.end_date&lt;br /&gt;
          @surveys &amp;lt;&amp;lt;&lt;br /&gt;
              [&lt;br /&gt;
                'survey' =&amp;gt; Questionnaire.find(survey_deployment.questionnaire_id),&lt;br /&gt;
                'survey_deployment_id' =&amp;gt; survey_deployment.id,&lt;br /&gt;
                'start_date' =&amp;gt; survey_deployment.start_date,&lt;br /&gt;
                'end_date' =&amp;gt; survey_deployment.end_date,&lt;br /&gt;
                'parent_id' =&amp;gt; p.parent_id,&lt;br /&gt;
                'participant_id' =&amp;gt; p.id,&lt;br /&gt;
                'global_survey_id' =&amp;gt; survey_deployment.global_survey_id&lt;br /&gt;
              ]&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==='''Integration Tests''===&lt;br /&gt;
23 integration tests were written to ensure the functionality works and also to make sure the refactoring does not break any of the existing functionality.&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109142</id>
		<title>CSC/ECE 517 Fall 2017/E1745 Refactor response controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1745_Refactor_response_controller.rb&amp;diff=109142"/>
		<updated>2017-10-22T00:18:40Z</updated>

		<summary type="html">&lt;p&gt;Dgupta10: Created page with &amp;quot;Testing&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Testing&lt;/div&gt;</summary>
		<author><name>Dgupta10</name></author>
	</entry>
</feed>