<?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=Sramase</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=Sramase"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Sramase"/>
	<updated>2026-05-11T22:43: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_Spring_2015_E1527_SWAR&amp;diff=96567</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96567"/>
		<updated>2015-04-09T03:05:06Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Scope */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are -&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:* review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
[[File:System Design.jpg|frame|center|upright=0.5|Web Service Design]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96566</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96566"/>
		<updated>2015-04-08T20:19:34Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 3.1 Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
[[File:System Design.jpg|frame|center|upright=0.5|Web Service Design]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96565</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96565"/>
		<updated>2015-04-08T20:19:22Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* List of Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
[[File:System Design.jpg|frame|center|upright=0.5|Web Service Design]]&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96564</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96564"/>
		<updated>2015-04-08T20:18:32Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 3.1 Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
[[File:System Design.jpg|frame|center|upright=0.5|Web Service Design]]&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96563</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96563"/>
		<updated>2015-04-08T20:17:25Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 3.1 Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
[[File:System Design.jpg|frame|center|Web Service Design]]&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96562</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96562"/>
		<updated>2015-04-08T20:16:41Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Standards */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96561</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96561"/>
		<updated>2015-04-08T20:16:14Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 3. Migrate gem to Web service */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&lt;br /&gt;
:* Refactoring the existing ruby classes&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
[[File:System Design.jpg]]&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well.  There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&lt;br /&gt;
===3.1 Design ===&lt;br /&gt;
&lt;br /&gt;
The Metareview system is Natural Language Processing based system that compares the reviews written with the original article. The webservice will expose the &amp;quot;AutomatedMetareview&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
The request JSON object to the method will have the following parameters :&lt;br /&gt;
:* original article&lt;br /&gt;
:* review written for this article&lt;br /&gt;
:* rubric used during article review.&lt;br /&gt;
&lt;br /&gt;
The web service will return the meta-review as a JSON object. The response JSON object will have the parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.2 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96557</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96557"/>
		<updated>2015-04-08T19:57:24Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 3. Migrate gem to Web service */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* plagiarism&lt;br /&gt;
:* relevance&lt;br /&gt;
:* content_summative&lt;br /&gt;
:* content_problem&lt;br /&gt;
:* content_advisory&lt;br /&gt;
:* coverage&lt;br /&gt;
:* tone_positive&lt;br /&gt;
:* tone_negative&lt;br /&gt;
:* tone_neutral&lt;br /&gt;
:* quantity&lt;br /&gt;
&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96556</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96556"/>
		<updated>2015-04-08T19:49:05Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Introduction to Autometareview project https://github.com/lramach/autometareviews0.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96555</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96555"/>
		<updated>2015-04-08T19:48:34Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* 2. Upgrade system to use latest dependent ruby gems */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &lt;br /&gt;
:* rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&lt;br /&gt;
:* bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96554</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96554"/>
		<updated>2015-04-08T19:47:38Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* List of Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
:* Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
:* WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96553</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96553"/>
		<updated>2015-04-08T19:47:06Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Scope */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
:* tone.rb &lt;br /&gt;
:* degree_of_relevance.rb &lt;br /&gt;
:* wordnet_based_similarity.rb &lt;br /&gt;
:* sentence_state.rb &lt;br /&gt;
:* cluster_generation.rb &lt;br /&gt;
:* plagiarism_check.rb &lt;br /&gt;
:* graph_generator.rb &lt;br /&gt;
:* predict_class.rb &lt;br /&gt;
:*review_coverage.rb &lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96552</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96552"/>
		<updated>2015-04-08T19:45:13Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Scope */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
:* Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
:* Migrating to newer libraries, wherever possible.&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
 tone.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; degree_of_relevance.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; wordnet_based_similarity.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; sentence_state.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; cluster_generation.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; plagiarism_check.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; graph_generator.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; predict_class.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; and review_coverage.rb &amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96551</id>
		<title>CSC/ECE 517 Spring 2015 E1527 SWAR</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1527_SWAR&amp;diff=96551"/>
		<updated>2015-04-08T19:43:32Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Scope */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1527. Refactor Autometareviews gem and migration to Web-Service&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
= Introduction to Autometareview project &amp;lt;ref&amp;gt;https://github.com/lramach/autometareviews0.1&amp;lt;/ref&amp;gt;=&lt;br /&gt;
This project is developed as part of Expertiza project &amp;lt;ref&amp;gt;http://wikis.lib.ncsu.edu/index.php/Expertiza&amp;lt;/ref&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
The automated metareview tool identifies the quality of a review using natural language processing and machine learning techniques (completely automated). Feedback is provided to reviewers on the following metrics:&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review relevance: This metric tells the reviewer how relevant the review is to the content of the author's submission. Numeric feedback in the scale of 0--1 is provided to indicate a review's relevance. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Content Type: This metric identifies whether the review contains 'summative content' -- positive feedback, problem detection content' -- problems identified by reviewers in the author's work or 'advisory content' -- content indicating suggestions or advice provided by reviewers. A numeric feedback on the scale of 0--1 is provided for each content type to indicate whether the review contains that type of content. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Review Coverage: This metric indicates the extent to which a review covers the main points of a submission. Numeric value in the range of 0--1 indicates the coverage of a review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Plagiarism&amp;lt;ref&amp;gt;http://www.plagiarism.org/plagiarism-101/what-is-plagiarism/&amp;lt;/ref&amp;gt;: Indicates the presence of plagiarism in the review text.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tone: The metric indicates whether a review has a positive, negative or neutral tone. &amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;Quantity: Indicates the number of unique words used by the reviewer in the review. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
&lt;br /&gt;
Currently, Autometareviews project is used as a gem&amp;lt;ref&amp;gt;http://guides.rubygems.org/what-is-a-gem/&amp;lt;/ref&amp;gt; in Expertiza project. Purpose of this project is to migrate this gem to a web service&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Web_service&amp;lt;/ref&amp;gt; and expose its methods on web, which can be consumed by any application as web service. Older gem was dependent old libraries&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/Library_%28computing%29&amp;lt;/ref&amp;gt;&lt;br /&gt;
such as Stanford-core-nlp, rwordnet, etc. We will migrate them to new libraries without breaking the existing feature-set. We are also going to refactor the source code of this gem file to promote readability, reduced complexity, and code redundancies. We will fix&lt;br /&gt;
any bug or bottleneck that we can find to improve the performance of this service. We will not add any new feature to the existing feature set provided by the gem. Before making any modification to the existing features, we will present them before Dr.&lt;br /&gt;
Gehringer and his Expertiza team.&lt;br /&gt;
&lt;br /&gt;
= Scope =&lt;br /&gt;
There are three separate scope items in this project -&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Migration of existing gem application to a web service&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Refactoring the existing ruby classes&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Migrating to newer libraries, wherever possible.&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The classes that we propose to refactor are&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
 tone.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; degree_of_relevance.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; wordnet_based_similarity.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; sentence_state.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; cluster_generation.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; plagiarism_check.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; graph_generator.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; predict_class.rb &amp;lt;/li&amp;gt;&amp;lt;li&amp;gt; and review_coverage.rb &amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No new feature will be developed as part of this project. Any major code change due to inclusion of newer libraries will be communicated to Expertiza project team. Existing code will be tested to ensure the functionality does not change.&lt;br /&gt;
&lt;br /&gt;
=Standards =&lt;br /&gt;
All developed code will adhere to the ruby on rails coding guidelines&amp;lt;ref&amp;gt;https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= List of Tasks =&lt;br /&gt;
Metioned below are the tasks we will perform as part of this project.&amp;lt;ref&amp;gt;https://docs.google.com/document/d/10JTdEjCiRTre3nO4j_czBzhcxkqOSzmAT8jyiJHNz4c/edit#&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This system is still in nascent stage and have many performance related issues. It takes a long time (about 2 minutes) to generate single meta-review. This is an unacceptable performance statistics for Expertiza. We propose to re-factor code and identify the areas that affect the overall performance of the system. Few areas we identified in preliminary review are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
Reading seed data from csv in each pass takes  up a lot of time. We can move this data into Mysql and use ActiveRecords to speed data fetch.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&lt;br /&gt;
WordNet based semantic matching takes a lot of time. We will review the method used and present our finding about areas of concern.&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Refactor Code==&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Efficient Loop constructs. &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many loops over models are implemented using generic “for” loops.&lt;br /&gt;
Solution: As specified by Ruby guideline, we plan to use efficient ruby loops, such as “each” and “find_each”.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Very large methods &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Several methods have huge amount of code, which makes them difficult to understand and debug.&lt;br /&gt;
Solution: In most cases, large methods can be shortened through the use of smaller helper methods. Such methods could be reused across different components.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Ambiguous method names &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Many methods have ambiguity between the name used for them and the feature implemented by them.&lt;br /&gt;
Solution: We will rename such methods to clearly state the feature implemented by them.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Legacy Code &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: As the system has been modified for bug fixes and enhancements, unnecessary code has accumulated.&lt;br /&gt;
Solution: Isolate and remove all dead code.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Code beautification &amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Description: Coding style used in gem is not based on Ruby on Rails style, which makes it difficult to read for any Ruby programmer.&lt;br /&gt;
Solution: Beautify the code with a consistent standard of documentation, and style.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Upgrade system to use latest dependent ruby gems ==&lt;br /&gt;
The libraries used by gem are very old. We plan to migrate the dependent libraries to their latest versions.&amp;lt;br /&amp;gt;&lt;br /&gt;
Libraries, we have identified are: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;stanford-core-nlp &amp;lt;ref&amp;gt;http://nlp.stanford.edu/software/corenlp.shtml&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rwordnet &amp;lt;ref&amp;gt;https://rubygems.org/gems/rwordnet&amp;lt;/ref&amp;gt; &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;rjb &amp;lt;ref&amp;gt;https://rubygems.org/gems/rjb&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;bind-it&amp;lt;ref&amp;gt;https://rubygems.org/gems/bind-it&amp;lt;/ref&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
We will also migrate the project to use Java 8&amp;lt;ref&amp;gt;http://java.com/en/download/whatis_java.jsp&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Migrate gem to Web service ==&lt;br /&gt;
Expertiza system tries to evaluate each review using an automated meta-review system. This system is packaged as a library and used by Expertiza. Automated Metareview system is an independent entity and can be used by other peer review systems as well. This is Natural Language Processing based system that accepts original article, review written for this article, and the rubric used during article review. There are many other peer review systems, which can benefit from this system, if this is available for them to evaluate their rubrics. We are working on migrating this system from a library to a web service. &lt;br /&gt;
&amp;lt;br /&amp;gt;Web service will expose &amp;quot;AutomatedMetareview&amp;quot; method, which will accept three parameters mentioned before as JSON and return the meta-review as a JSON object. &amp;lt;br /&amp;gt;&lt;br /&gt;
The response JSON object will have parameters mentioned below: &amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;plagiarism&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;relevance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_summative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;content_advisory&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;coverage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_positive&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_negative&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;tone_neutral&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;quantity&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
[[File:Workflow.jpg|frame|center|Interaction between Client and Web Service]]&lt;br /&gt;
&lt;br /&gt;
===3.1 Assumptions===&lt;br /&gt;
For the project, the code that is being modified is assumed to be correct and meet all feature requirements of the system. Interactions modified due to refactoring will not change the underline system definitions.&lt;br /&gt;
&lt;br /&gt;
== 4. Testing==&lt;br /&gt;
We will be using the existing test suite used by gem to test any new code modification. We will be writing new test cases for web service implementation and any new public method exposed by existing classes.&lt;br /&gt;
&lt;br /&gt;
= References =&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96078</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96078"/>
		<updated>2015-03-31T04:05:50Z</updated>

		<summary type="html">&lt;p&gt;Sramase: Undo revision 96077 by Sramase (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;In order to run our code vist: 152.46.20.14:1 (VNC Viewer) or 152.46.20.14:5801 (browser), and use the password: password to log in. Please leave the system like you found it (with the browser open, and set to localhost:3000).&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out. Could not move the logic for creating new reviews out of rereview since the new reviews were not created by rereview but instead was using the create method in response_controller.rb&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96077</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96077"/>
		<updated>2015-03-31T04:04:36Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing duplicate methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;In order to run our code vist: 152.46.20.14:1 (VNC Viewer) or 152.46.20.14:5801 (browser), and use the password: password to log in. Please leave the system like you found it (with the browser open, and set to localhost:3000).&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out. Could not move the logic for creating new reviews out of rereview since the new reviews were not created by rereview but instead was using the create method in response_controller.rb&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant&lt;br /&gt;
      .where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      .where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap&lt;br /&gt;
        .create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant&lt;br /&gt;
                .where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap&lt;br /&gt;
                .where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap&lt;br /&gt;
        .create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant&lt;br /&gt;
        .where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap&lt;br /&gt;
        .where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap&lt;br /&gt;
        .create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96076</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=96076"/>
		<updated>2015-03-31T04:02:56Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Renaming latestResponseVersion method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;In order to run our code vist: 152.46.20.14:1 (VNC Viewer) or 152.46.20.14:5801 (browser), and use the password: password to log in. Please leave the system like you found it (with the browser open, and set to localhost:3000).&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out. Could not move the logic for creating new reviews out of rereview since the new reviews were not created by rereview but instead was using the create method in response_controller.rb&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) &lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95976</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95976"/>
		<updated>2015-03-24T04:11:57Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Response Controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out. Could not move the logic for creating new reviews out of rereview since the new reviews were not created by rereview but instead was using the create method in response_controller.rb&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95975</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95975"/>
		<updated>2015-03-24T04:10:51Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Response Controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out. Could not change the logic for creating new reviews since rereview was not actually creating the new review but instead was using the create method in response_controller.rb&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95974</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95974"/>
		<updated>2015-03-24T04:08:40Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing special code in rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95973</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95973"/>
		<updated>2015-03-24T04:08:23Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Moving the sorting of response versions logic out of rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95972</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95972"/>
		<updated>2015-03-24T04:07:44Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Renaming latestResponseVersion method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95971</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95971"/>
		<updated>2015-03-24T04:07:07Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Re-factored Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Renaming latestResponseVersion method==&lt;br /&gt;
The latestResponseVersion method is misnamed. It fetches all the previous versions of a response and its current name does not reflect its actual functionality. The method was renamed as previous_responses since it better suited the actual functionality.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def latestResponseVersion&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
     for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
 def previous_responses&lt;br /&gt;
    #get all previous versions of responses for the response map.&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.where(map_id: @map.id)&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method create&lt;br /&gt;
&lt;br /&gt;
    @map = ResponseMap.find(params[:id]) #assignment/review/metareview id is in params id&lt;br /&gt;
    @res = 0&lt;br /&gt;
    msg = &amp;quot;&amp;quot;&lt;br /&gt;
    error_msg = &amp;quot;&amp;quot;&lt;br /&gt;
    previous_responses&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95970</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95970"/>
		<updated>2015-03-24T03:59:07Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Moving sorting Responses logic out of rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving the sorting of response versions logic out of rereview method==&lt;br /&gt;
The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method was becoming very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95969</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95969"/>
		<updated>2015-03-24T03:58:11Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Re-factored Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving sorting Responses logic out of rereview method==&lt;br /&gt;
The rereview method has many parts that can be made into separate methods. The code to sort response versions has been moved from rereview method to a separate method. This was done because the rereview method has become very long and confusing.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
    get_content&lt;br /&gt;
    array_not_empty=0&lt;br /&gt;
    @review_scores=Array.new&lt;br /&gt;
    @prev=Response.all&lt;br /&gt;
    #get all versions and find the latest version&lt;br /&gt;
    for element in @prev&lt;br /&gt;
      if (element.map.id==@map.map.id)&lt;br /&gt;
        array_not_empty=1&lt;br /&gt;
        @review_scores &amp;lt;&amp;lt; element&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    latestResponseVersion&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
      @largest_version_num=@sorted[0]&lt;br /&gt;
      @latest_phase=@largest_version_num.created_at&lt;br /&gt;
      due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
      @sorted_deadlines=Array.new&lt;br /&gt;
      @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
      current_time=Time.new.getutc&lt;br /&gt;
      #get the highest version numbered review&lt;br /&gt;
      next_due_date=@sorted_deadlines[0]&lt;br /&gt;
      #check in which phase the latest review was done.&lt;br /&gt;
      for deadline_version in @sorted_deadlines&lt;br /&gt;
        if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
          break&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
   def rereview&lt;br /&gt;
    @map=ResponseMap.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
    # store response content in map&lt;br /&gt;
    get_content&lt;br /&gt;
&lt;br /&gt;
    previous_responses&lt;br /&gt;
    #sort all the available versions in descending order.&lt;br /&gt;
    if @prev.present?&lt;br /&gt;
      sortResponseVersion&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 def sortResponseVersion&lt;br /&gt;
    @sorted=@review_scores.sort { |m1, m2| (m1.version_num and m2.version_num) ? m2.version_num &amp;lt;=&amp;gt; m1.version_num : (m1.version_num ? -1 : 1) }&lt;br /&gt;
    @largest_version_num=@sorted[0]&lt;br /&gt;
    @latest_phase=@largest_version_num.created_at&lt;br /&gt;
    due_dates = DueDate.where([&amp;quot;assignment_id = ?&amp;quot;, @assignment.id])&lt;br /&gt;
    @sorted_deadlines=Array.new&lt;br /&gt;
    @sorted_deadlines=due_dates.sort { |m1, m2| (m1.due_at and m2.due_at) ? m1.due_at &amp;lt;=&amp;gt; m2.due_at : (m1.due_at ? -1 : 1) }&lt;br /&gt;
    current_time=Time.new.getutc&lt;br /&gt;
    #get the highest version numbered review&lt;br /&gt;
    next_due_date=@sorted_deadlines[0]&lt;br /&gt;
    #check in which phase the latest review was done.&lt;br /&gt;
    for deadline_version in @sorted_deadlines&lt;br /&gt;
      if (@largest_version_num.created_at &amp;lt; deadline_version.due_at)&lt;br /&gt;
        break&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    for deadline_time in @sorted_deadlines&lt;br /&gt;
      if (current_time &amp;lt; deadline_time.due_at)&lt;br /&gt;
        break&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;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95607</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95607"/>
		<updated>2015-03-23T05:24:04Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing special code in rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
       #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      #else create a new version and update it.&lt;br /&gt;
      @header = &amp;quot;New&amp;quot;&lt;br /&gt;
      @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
      @feedback = params[:feedback]&lt;br /&gt;
      @map = ResponseMap.find(params[:id])&lt;br /&gt;
      @return = params[:return]&lt;br /&gt;
      @modified_object = @map.map_id&lt;br /&gt;
      get_content&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95606</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95606"/>
		<updated>2015-03-23T05:22:10Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing special code in rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95605</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95605"/>
		<updated>2015-03-23T05:21:29Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing special code in rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      In method rereview&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  In method rereview&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|&lt;br /&gt;
 #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95604</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95604"/>
		<updated>2015-03-23T05:18:34Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Removing special code in rereview method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95603</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95603"/>
		<updated>2015-03-23T05:17:43Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Re-factored Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Removing special code in rereview method==&lt;br /&gt;
The rereview method had some special code to check if the current user is jace_smith and uses a custom hard-coded rubric instead of a rubric from the system. This was a code segment that was written when multipart rubrics were first tested. Removing this code will break the assignment and so the code was moved to a separate method and commented as a kludge.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      #**********************&lt;br /&gt;
      # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        if @assignment.id &amp;lt; 469&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response'&lt;br /&gt;
        else&lt;br /&gt;
          @next_action = &amp;quot;create&amp;quot;&lt;br /&gt;
          render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
        end&lt;br /&gt;
      else&lt;br /&gt;
        # end of special code (except for the end below, to match the if above)&lt;br /&gt;
        #**********************&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  Line 73&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else &lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
  Line 88&lt;br /&gt;
  # Check whether this is Jen's assgt. &amp;amp; if so, use her rubric&lt;br /&gt;
      if (@assignment.instructor_id == User.find_by_name(&amp;quot;jace_smith&amp;quot;).id) &amp;amp;&amp;amp; @title == &amp;quot;Review&amp;quot;&lt;br /&gt;
        handle_jens_assignment&lt;br /&gt;
      else&lt;br /&gt;
        render :action =&amp;gt; 'response'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  #kludge for checking if assignment is jen's assignment and using her rubric if it is&lt;br /&gt;
  def handle_jens_assignment&lt;br /&gt;
    if @assignment.id &amp;lt; 469&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response'&lt;br /&gt;
    else&lt;br /&gt;
      @next_action = &amp;quot;update&amp;quot;&lt;br /&gt;
      render :action =&amp;gt; 'custom_response_2011'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95593</id>
		<title>CSC/ECE 517 Fall 2014/oss E1508 MRS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2014/oss_E1508_MRS&amp;diff=95593"/>
		<updated>2015-03-23T04:18:28Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Response Controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1508 Refactoring Response Controller'''&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the ResponseController.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Introduction to Expertiza=&lt;br /&gt;
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). The Expertiza project is supported by the National Science Foundation.&amp;lt;ref&amp;gt;[http://expertiza.ncsu.edu/ Expertiza]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://wikis.lib.ncsu.edu/index.php/Expertiza Wiki]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Problem Statement =&lt;br /&gt;
'''Classes involved:'''&lt;br /&gt;
 response_controller.rb&lt;br /&gt;
 response.rb&lt;br /&gt;
&lt;br /&gt;
'''What they do:'''&lt;br /&gt;
Allows the user to create and edit responses to questionnaires … such as performing a review, rating a teammate, or giving feedback to a reviewer.&lt;br /&gt;
&lt;br /&gt;
'''What's wrong with it:'''&lt;br /&gt;
* It doesn’t do authorization properly.&lt;br /&gt;
* It contains duplicated methods.&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
&lt;br /&gt;
'''What needs to be done:'''&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;latestresponseversion&amp;lt;/font&amp;gt; seems misnamed.  It fetches all previous versions of a response (which is to say, all previous review versions by the current reviewer of the current author for the current assignment).&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;get_scores&amp;lt;/font&amp;gt; gets all the scores assigned in a particular response.  A “response” is created when someone submits a review, a partner evaluation, a survey, etc.&lt;br /&gt;
# The &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; method is 98 lines long.  Several parts of it should be turned into methods.  Sorting review versions is really not a controller responsibility; it would be better to do this in a model class (which class?)  Ditto for determining whether a review is current (i.e., was done during the current assignment phase).  This is a query that is made about a review (actually, about a response, which may be a review, author feedback, etc.).  It should be placed in the appropriate model class.&lt;br /&gt;
# &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt; contains special code to check whether an assignment is “Jen’s assignment”; this was the first assignment we ever created with a multipart rubric.  It was hard-coded into the system, rather than working on a rubric that was created in the normal way.  It is probably impossible to remove this code without breaking that assignment, but it should be done in a separate method, and commented appropriately as a kludge.&lt;br /&gt;
# Again in &amp;lt;font face=Courier New&amp;gt;rereview&amp;lt;/font&amp;gt;, creating a new version of a review is a model responsibility, and should be moved out of the controller.&lt;br /&gt;
# There are two (consecutive) copies of the &amp;lt;font face=Courier New&amp;gt;edit&amp;lt;/font&amp;gt; method.  The second appears to be the newer one, and, according to the rules for method definition, is the one that is currently in use.  The first should be removed.   Ditto for &amp;lt;font face=Courier New&amp;gt;new_feedback&amp;lt;/font&amp;gt; and &amp;lt;font face=Courier New&amp;gt;view&amp;lt;/font&amp;gt;--the 2nd version of each appears to be newer &amp;amp; should be kept.&lt;br /&gt;
# Authorization to perform actions is not checked correctly.  It is supposed to be done through the &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method at the beginning of the class definition.  Different authorization should be required for different operations.  For example, someone should be allowed to view a response if they wrote the response, or they are the person or on the team whose work the response applied to, or if they are an instructor or TA for the class.  The person who wrote a response should be allowed to edit it, but not the person/team who was being reviewed, nor the instructor or TA for the class. Currently, authorization is denied by the &amp;lt;font face=Courier New&amp;gt;redirect_when_disallowed&amp;lt;/font&amp;gt; method, which was an earlier, more error-prone way of controlling access.  It should go away, now that the class has an &amp;lt;font face=Courier New&amp;gt;action_allowed?&amp;lt;/font&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
=Changes Made=&lt;br /&gt;
&lt;br /&gt;
==Response Controller==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| latestResponseVersion&lt;br /&gt;
| Changed name to previous_responses&lt;br /&gt;
| The name wasn't indicative of what the method did&lt;br /&gt;
|-&lt;br /&gt;
| new_feedback&lt;br /&gt;
| Deleted the old new_feedback method&lt;br /&gt;
| The old new_feedback method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| view&lt;br /&gt;
| Deleted the old view method&lt;br /&gt;
| The old view method was not getting called due to ruby rules&lt;br /&gt;
|-&lt;br /&gt;
| redirect_when_disallowed&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Moved all of the code from redirect_when_disallowed to action_allowed and deleted all of the previous references (action_allowed? gets called automatically)&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Authorization to perform actions wasn't being performed correctly, it is supposed to be done through action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| action_allowed?&lt;br /&gt;
|-&lt;br /&gt;
| rereview&lt;br /&gt;
| Moved logic for sorting response versions, and for getting the latest response to their own methods. The method had some special code that was moved out.&lt;br /&gt;
| The rereview method was becoming too large and confusing&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Response Model==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|Method Name&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Changes Made &lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Reason For Change&lt;br /&gt;
|-&lt;br /&gt;
| get_scores&lt;br /&gt;
| Moved from controller (response_controller.rb) to model (response.rb)&lt;br /&gt;
| The functionality in get_scores makes more sense to be implemented in the Model rather than in the controller&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Re-factored Code =&lt;br /&gt;
&lt;br /&gt;
==Removing duplicate methods==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, and the functionality changed over time, causing two new_feedback and view methods to be created; the oldest of which doesn't get called anymore.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.map_id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def new_feedback&lt;br /&gt;
    review = Response.find(params[:id])&lt;br /&gt;
    if review&lt;br /&gt;
      reviewer = AssignmentParticipant.where(user_id: session[:user].id, parent_id:  review.map.assignment.id).first&lt;br /&gt;
      map = FeedbackResponseMap.where(reviewed_object_id: review.id, reviewer_id:  reviewer.id).first&lt;br /&gt;
      if map.nil?&lt;br /&gt;
        #if no feedback exists by dat user den only create for dat particular response/review&lt;br /&gt;
        map = FeedbackResponseMap.create(:reviewed_object_id =&amp;gt; review.id, :reviewer_id =&amp;gt; reviewer.id, &lt;br /&gt;
                                         :reviewee_id =&amp;gt; review.map.reviewer.id)&lt;br /&gt;
      end&lt;br /&gt;
      redirect_to :action =&amp;gt; 'new', :id =&amp;gt; map.id, :return =&amp;gt; &amp;quot;feedback&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      redirect_to :back&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|- style=&amp;quot;vertical-align:bottom;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if redirect_when_disallowed(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    @review_scores = Array.new&lt;br /&gt;
    @question_type = Array.new&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score.where(response_id: @map.response_id, question_id:  question.id).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def view&lt;br /&gt;
    @response = Response.find(params[:id])&lt;br /&gt;
    return if action_allowed?(@response)&lt;br /&gt;
    @map = @response.map&lt;br /&gt;
    get_content&lt;br /&gt;
    get_scores(@response, @questions)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving code to the proper place==&lt;br /&gt;
The ResponseController allows the user to create and edit responses to questionnaires, in doing so, there needs to be some sort of authentication, and the proper place for that is in the action_allowed? method, however the un-refactored code did in the redirect_when_disallowed method. Moreover, once this code was moved to the action_allowed? method, all of the references to redirect_when_disallowed were removed (action_allowed? gets called automatically).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
def action_allowed?&lt;br /&gt;
    current_user&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
def redirect_when_disallowed(response)&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    !current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
  def action_allowed?&lt;br /&gt;
    # For author feedback, participants need to be able to read feedback submitted by other teammates.&lt;br /&gt;
    # If response is anything but author feedback, only the person who wrote feedback should be able to see it.&lt;br /&gt;
    if Response.where(id: params[:id]).empty?&lt;br /&gt;
      true&lt;br /&gt;
    elsif&lt;br /&gt;
    response = Response.find(params[:id])&lt;br /&gt;
    if response.map.read_attribute(:type) == 'FeedbackResponseMap' &amp;amp;&amp;amp; response.map.assignment.team_assignment?&lt;br /&gt;
      team = response.map.reviewer.team&lt;br /&gt;
      unless team.has_user session[:user]&lt;br /&gt;
        redirect_to '/denied?reason=You are not on the team that wrote this feedback'&lt;br /&gt;
      else&lt;br /&gt;
        return false&lt;br /&gt;
      end&lt;br /&gt;
      response.map.read_attribute(:type)&lt;br /&gt;
    end&lt;br /&gt;
    current_user_id?(response.map.reviewer.user_id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Moving get_scores to the Response Model==&lt;br /&gt;
The get_scores method was being implemented in the controller. Its function fits better in the model.&lt;br /&gt;
As such, the method was moved and changed to retain the functionality of code that uses it. Since the variables it requires were no longer in scope, they're passed in as arguments. Also due to scope, the result has to be explicitly returned.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! |Before Changes&lt;br /&gt;
! |After Changes &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores&lt;br /&gt;
    @review_scores = []&lt;br /&gt;
    @question_type = []&lt;br /&gt;
    @questions.each do |question|&lt;br /&gt;
      @review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
        .where(&lt;br /&gt;
          response_id: @response.id,&lt;br /&gt;
          question_id:  question.id&lt;br /&gt;
        ).first&lt;br /&gt;
      @question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&lt;br /&gt;
In response.rb&lt;br /&gt;
&lt;br /&gt;
def get_scores(response, questions)&lt;br /&gt;
    review_scores = []&lt;br /&gt;
    question_type = []&lt;br /&gt;
    questions.each do |question|&lt;br /&gt;
      review_scores &amp;lt;&amp;lt; Score&lt;br /&gt;
                            .where(&lt;br /&gt;
                                response_id: response.id,&lt;br /&gt;
                                question_id:  question.id&lt;br /&gt;
                            ).first&lt;br /&gt;
      question_type &amp;lt;&amp;lt; QuestionType.find_by_question_id(question.id)&lt;br /&gt;
    end&lt;br /&gt;
      question_type&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In response_controller.rb&lt;br /&gt;
&lt;br /&gt;
def view&lt;br /&gt;
     @response = Response.find(params[:id])&lt;br /&gt;
     @map = @response.map&lt;br /&gt;
     get_content&lt;br /&gt;
     @question_type = @response.get_scores(@response, @questions)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Steps to verify changes=&lt;br /&gt;
&lt;br /&gt;
==Action Allowed==&lt;br /&gt;
Action allowed is called before every method call to confirm whether or not the currently logged in user has the required privileges to complete the requested action.&lt;br /&gt;
To test the functionality of this method one has to attempt to complete an action that they have privileges to complete, and confirm that they're allowed to complete it. One also has to attempt to complete an action that they don't have the privileges to complete, and confirm that they're not allowed to complete it.&lt;br /&gt;
&lt;br /&gt;
===Allowed===&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedPass.png]]&lt;br /&gt;
&lt;br /&gt;
===Not Allowed===&lt;br /&gt;
Log into the application with the user having an instructor's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user6, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
&lt;br /&gt;
# Click on Assignments, and you should see the following:&lt;br /&gt;
&lt;br /&gt;
[[File:actionallowedFail.png]]&lt;br /&gt;
&lt;br /&gt;
== get_scores  ==&lt;br /&gt;
Get scores is called anytime the scores for reviews are shown. Given that, the way to test its correct functionality is to navigate to a completed review and make sure the scores are shown and are correct.&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Review done at --2013-03-01 23:57:55 UTC&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the get_scores method.&lt;br /&gt;
&lt;br /&gt;
== rereview  ==&lt;br /&gt;
Rereview manages the versioning of multiple reviews for the same assignment. To test the correct functionality of review, one should attempt to update a review (i.e. 'rereview').&lt;br /&gt;
&lt;br /&gt;
Log into the application with the user having a student's role (&amp;lt;b&amp;gt;User Id:&amp;lt;/b&amp;gt; user5072, &amp;lt;b&amp;gt;Password:&amp;lt;/b&amp;gt; password)&lt;br /&gt;
# Click on Assignments&lt;br /&gt;
# Click on Writing assignment 1b, Spring 2013&lt;br /&gt;
# Click on Others' Work&lt;br /&gt;
# Click on Update (beside Metaprogramming in dynamically typed languages)&lt;br /&gt;
&lt;br /&gt;
Successful loading of this page confirms the rereview method.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references&amp;gt;&amp;lt;/references&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93530</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93530"/>
		<updated>2015-02-09T16:20:28Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Ruby and Amazon S3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Representational_state_transfer Wikipedia: REST]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html S3 Introduction]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK &amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt; that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/RubyGems Wikipedia: RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93529</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93529"/>
		<updated>2015-02-09T16:19:55Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Representational_state_transfer Wikipedia: REST]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html S3 Introduction]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK &amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt; that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93528</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93528"/>
		<updated>2015-02-09T16:19:30Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html S3 Introduction]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK &amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt; that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93527</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93527"/>
		<updated>2015-02-09T16:18:31Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Ruby and Amazon S3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer REST]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html S3 Introduction]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK &amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt; that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93526</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93526"/>
		<updated>2015-02-09T16:17:55Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Objects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer REST]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html S3 Introduction]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93525</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93525"/>
		<updated>2015-02-09T16:16:35Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer REST]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html Amazon S3]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/ Amazon S3 Homepage]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816 Amazon Press Release]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982 Amazon Press Release]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html Happy birthday Amazon S3]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/ amazon s3 now]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/ Upload promotion]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083 Amazons Head Start in the Cloud]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/ Two trillion objects]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93524</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93524"/>
		<updated>2015-02-09T16:12:33Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects; April of 2007, 5 billion objects; October of 2007, 10 billion; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html Using Objects]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html Using Bucket]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html Using Metadata]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html Versioning]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html Access Control]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html Data Durability]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html Using the Ruby API]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93523</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93523"/>
		<updated>2015-02-09T16:08:26Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Ruby and Amazon S3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; April of 2007, 5 billion objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October of 2007, 10 billion&amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93522</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93522"/>
		<updated>2015-02-09T16:08:13Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Data Protection */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; April of 2007, 5 billion objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October of 2007, 10 billion&amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems&amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93521</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93521"/>
		<updated>2015-02-09T16:06:44Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; April of 2007, 5 billion objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October of 2007, 10 billion&amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems&amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93520</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93520"/>
		<updated>2015-02-09T16:05:40Z</updated>

		<summary type="html">&lt;p&gt;Sramase: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol]&amp;lt;/ref&amp;gt;, or SOAP &amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/SOAP]&amp;lt;/ref&amp;gt; making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]&amp;lt;/ref&amp;gt;. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ &amp;lt;ref&amp;gt;[http://aws.amazon.com/s3/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ref&amp;gt;[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816]&amp;lt;/ref&amp;gt; and in Europe in November of 2007 &amp;lt;ref&amp;gt;[http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]&amp;lt;/ref&amp;gt;. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; April of 2007, 5 billion objects &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October of 2007, 10 billion&amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; Jan 2008, 14 billion &amp;lt;ref&amp;gt;[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]&amp;lt;/ref&amp;gt;; October 2008, 29 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-now/]&amp;lt;/ref&amp;gt;; March 2009, 52 billion &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]&amp;lt;/ref&amp;gt;; August 2009, 64 billion &amp;lt;ref&amp;gt;[http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]&amp;lt;/ref&amp;gt;. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! &amp;lt;ref&amp;gt;[https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]&amp;lt;/ref&amp;gt;. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK (&amp;lt;ref&amp;gt;[http://rubygems.org/gems/aws-sdk| download]&amp;lt;/ref&amp;gt;) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems&amp;lt;ref&amp;gt;[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the &amp;lt;ref&amp;gt;[http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html]&amp;lt;/ref&amp;gt; -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about&amp;lt;ref&amp;gt;['content-length']}\t#{object.about&amp;lt;ref&amp;gt;['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = &amp;lt;ref&amp;gt;[]&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following &amp;lt;ref&amp;gt;[http://aws.amazon.com/apache-2-0/ license]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - &amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93519</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93519"/>
		<updated>2015-02-09T15:59:28Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Data Protection */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&amp;lt;ref&amp;gt;[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93518</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93518"/>
		<updated>2015-02-09T15:51:36Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93517</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93517"/>
		<updated>2015-02-09T15:50:38Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Data Protection */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.[http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93516</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93516"/>
		<updated>2015-02-09T15:50:19Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
====Access Permissions====&lt;br /&gt;
&lt;br /&gt;
All resources(buckets,objects etc) are private in Amazon S3 by default. Only the resource owner can access the resource and can grant access to other users to accesss the resource. There are two types of access policies in S3 - Resource-based and user policies. Resource-based policies are attached to a particular resource and user policies are assigned to a particular user.[http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html]&lt;br /&gt;
&lt;br /&gt;
====Data Protection====&lt;br /&gt;
&lt;br /&gt;
Objects are redundantly stored on multiple devices across multiple facilities within a region for durability. To improve durability, write requests do not return success before storing the data across multiple facilities. Also checksums are used to verify data integrity. If any corruption is detected, it is repaired using redundant data.&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93505</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93505"/>
		<updated>2015-02-09T14:36:10Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93504</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93504"/>
		<updated>2015-02-09T14:35:43Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html| AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93503</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93503"/>
		<updated>2015-02-09T14:35:19Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html | AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93501</id>
		<title>CSC/ECE 517 Spring 2015/ch1a 7 SA</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1a_7_SA&amp;diff=93501"/>
		<updated>2015-02-09T14:34:36Z</updated>

		<summary type="html">&lt;p&gt;Sramase: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:S3.gif|frame|Source: http://www.w7cloud.com/7-reasons-to-use-amazon-s3-cloud-computing-online-storage/|right]] Amazon Simple Storage Service (Amazon S3) is a remote, scalable, secure, and cost efficient storage space service provided by Amazon. Users are able to access their storage on Amazon S3 from the web via REST &amp;lt;ref&amp;gt;Wikipedia: REST[http://en.wikipedia.org/wiki/Representational_state_transfer]&amp;lt;/ref&amp;gt; HTTP [http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol], or SOAP [http://en.wikipedia.org/wiki/SOAP] making their data accessible from virtually anywhere in the world. Amazon S3 implements redundancy across multiple devices on multiple facilities in order to safeguard against application failure ,data loss and minimization of downtime [http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonS3.html]. Some of the most prominent users of Amazon S3 include: Netflix, SmugMug, Wetransfer, Pinterest, and NASDAQ [http://aws.amazon.com/s3/].&lt;br /&gt;
&lt;br /&gt;
[https://docs.google.com/a/ncsu.edu/document/d/1TgBtp7flIPKJwkkShgtcIkt--mtHuwVHsQX6Tpzj1rc/edit Writing Assignment 1a]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
Amazon S3 launched in March of 2006 in the United States [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=830816] and in Europe in November of 2007 [http://phx.corporate-ir.net/phoenix.zhtml?c=176060&amp;amp;p=irol-newsArticle&amp;amp;ID=1072982]. Since its inception, Amazon S3 has reported tremendous growth. Beginning in July of 2006, S3 hosted 800 million objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; April of 2007, 5 billion objects [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October of 2007, 10 billion[http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; Jan 2008, 14 billion [http://www.allthingsdistributed.com/2008/03/happy_birthday_amazon_s3.html]; October 2008, 29 billion [https://aws.amazon.com/blogs/aws/amazon-s3-now/]; March 2009, 52 billion [https://aws.amazon.com/blogs/aws/celebrating-s3s-third-birthday-with-an-upload-promotion/]; August 2009, 64 billion [http://www.eweek.com/c/a/Cloud-Computing/Amazons-Head-Start-in-the-Cloud-Pays-Off-584083]. In April of 2013, S3 now hosts more than 2 trillion objects and on average 1.1 million requests every second! [https://aws.amazon.com/blogs/aws/amazon-s3-two-trillion-objects-11-million-requests-second/].&lt;br /&gt;
&lt;br /&gt;
===Design===&lt;br /&gt;
&lt;br /&gt;
S3 is an example of an object storage and is not like a traditional hierarchical file system. S3 exposes a simple feature set to improve robustness and all data in S3 is accessed in the terms of objects and buckets. &lt;br /&gt;
&lt;br /&gt;
====Objects====&lt;br /&gt;
&lt;br /&gt;
Objects are the basic units of storage in Amazon S3. Each object is composed of object data and metadata. S3 supports a size of up to 5 Terabytes per object. Each object has a metadata part that is used to identify the object. Metadata is a set of name-value pairs that describe the object like date modified. Custom data about the object can be stored in metadata by the user. Every object is identified by a user defined key and is versioned by default. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html]. An object consists of the following - Key, Version ID, Value, Metadata, Subresources and Access Control Information. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingObjects.html]&lt;br /&gt;
&lt;br /&gt;
====Buckets====&lt;br /&gt;
&lt;br /&gt;
A bucket is a container for objects and every object must be part of a bucket. Any number of objects can be part of a Bucket. Buckets can be configured to be hosted in a particular region (US, EU, Asia Pacific etc.) in order to optimize latency. S3 limits the number of buckets per account to 100. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html]&lt;br /&gt;
&lt;br /&gt;
====Keys and Metadata====&lt;br /&gt;
&lt;br /&gt;
An user specifies a key to an object on creation which is used to uniquely identify the object in the bucket. These names acts as the keys for the objects and can be at most 1024 bytes long.&lt;br /&gt;
&lt;br /&gt;
There are two kinds of metadata for an object - System metadata and Object metadata. System metadata is used by S3 for object management. For eg. - Data, Content-Type etc. are stored as System metadata. Object metadata is optional and can be used by the user to add additional metadata to the objects while object creation. [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html]&lt;br /&gt;
&lt;br /&gt;
====Regions====&lt;br /&gt;
&lt;br /&gt;
Regions allow a user to specify the geographical region where the buckets will be stored. This can be used to optimize latency and minimizing costs.&lt;br /&gt;
S3 supports the following regions - US Standard, US West (Oregon) region, US West (N. California) region, EU (Ireland) region, EU (Frankfurt) region, Asia Pacific (Singapore) region, Asia Pacific (Tokyo) region, Asia Pacific (Sydney) region, South America (Sao Paulo) region [http://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#Regions]&lt;br /&gt;
&lt;br /&gt;
====Versioning====&lt;br /&gt;
&lt;br /&gt;
All objects in S3 are versioned by default and it can be used to retrieve and restore every version of an object in a bucket. Every change to an object(create, modify, delete) results in a separate version of the object which can be later used for restoring or recovery. Versioning is done at the bucket level and not for individual objects. It can be turned off or on per bucket but a versioned-enabled bucket cannot be turned to an unversioned bucket. Versioning can only be paused in these cases. [http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html]&lt;br /&gt;
&lt;br /&gt;
===Ruby and Amazon S3===&lt;br /&gt;
&lt;br /&gt;
Amazon Web Services (AWS) provides an SDK ([http://rubygems.org/gems/aws-sdk| download]) that works with Ruby for many amazon webservices, including Amazon S3. Developers new to the Amazon AWS SDK should begin with version 2 as it includes many built in features such as waiters, automatically paginated responses, and a streamlined plugin style architecture. Version 2 of the SDK has 2 &amp;quot;packages&amp;quot;, also referred to as &amp;quot;gems&amp;quot; &amp;lt;ref&amp;gt;Wikipedia: Ruby Gems[http://en.wikipedia.org/wiki/RubyGems|RubyGems]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:* '''aws-sdk-core''' - provides a direct mapping to the AWS APIs including automatic response paging, waiters, parameter validation, and Ruby type support&lt;br /&gt;
:* '''aws-sdk-resources'''  - provides an object-oriented abstraction over low-level interfaces in the core to reduce the complexity of utilizing core interfaces; resource objects reference other objects such as an Amazon S3 instance and the attributes and actions as instance variables and methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It should also be noted that there exists a Version 1 of the aws sdk that lacks some &amp;quot;convenience features&amp;quot; otherwise available in version 2 of the sdk. For more information see the [http://ruby.awsblog.com/post/Tx2OMCYFEZX2I6A/AWS-SDK-for-Ruby-V2-Preview-Release|AWS Ruby Development Blog]&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
There are 3 key classes in AWS SDK [http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPRubyAPI.html] -&lt;br /&gt;
&lt;br /&gt;
:* '''AWS::S3''' - Denotes an interface to Amazon S3 for the Ruby SDK. It has the ''#buckets'' instance method for creating new buckets or accessing existing buckets.&lt;br /&gt;
:* '''AWS::S3::Bucket''' - Denotes an Amazon S3 Bucket. It provides the ''#objects'' instance method to access existing objects and also other methods to get information about a bucket.&lt;br /&gt;
:* '''AWS::S3::S3Object''' - Denotes an Amazon S3 Object. It provides the method that gives information about the object and also setting access permissions, copying, deleting and uploading objects.&lt;br /&gt;
&lt;br /&gt;
See the following link for the documentation for AWS SDK - [http://docs.aws.amazon.com/AWSRubySDK/latest/_index.html|AWS SDK for Ruby]&lt;br /&gt;
&lt;br /&gt;
===Creating a connection to S3 server===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Base.establish_connection!(&lt;br /&gt;
        :server            =&amp;gt; 'objects.example.com',&lt;br /&gt;
        :use_ssl           =&amp;gt; true,&lt;br /&gt;
        :access_key_id     =&amp;gt; 'my-access-key',&lt;br /&gt;
        :secret_access_key =&amp;gt; 'my-secret-key'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing all buckets you own===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Service.buckets.each do |bucket|&lt;br /&gt;
        puts &amp;quot;#{bucket.name}\t#{bucket.creation_date}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expected output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mybuckat1   2011-04-21T18:05:39.000Z&lt;br /&gt;
mybuckat2   2011-04-21T18:05:48.000Z&lt;br /&gt;
mybuckat3   2011-04-21T18:07:18.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Listing a bucket's contents===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new_bucket = AWS::S3::Bucket.find('my-new-bucket')&lt;br /&gt;
new_bucket.each do |object|&lt;br /&gt;
        puts &amp;quot;#{object.key}\t#{object.about['content-length']}\t#{object.about['last-modified']}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected output'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file1.filex 251262  2011-08-08T21:35:48.000Z&lt;br /&gt;
file2.filex 262518  2011-08-08T21:38:01.000Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting a bucket===&lt;br /&gt;
:'''Note:''''' The target bucket must be empty!''&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Forced removal of non-empty buckets===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::Bucket.delete('my-new-bucket', :force =&amp;gt; true)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Creating an object===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.store(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'Hello World!',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :content_type =&amp;gt; 'text/plain'&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Change an object's ACL (access control list)===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
policy = AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = [ AWS::S3::ACL::Grant.grant(:public_read) ]&lt;br /&gt;
AWS::S3::S3Object.acl('hello.txt', 'my-new-bucket', policy)&lt;br /&gt;
&lt;br /&gt;
policy = AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket')&lt;br /&gt;
policy.grants = []&lt;br /&gt;
AWS::S3::S3Object.acl('secret_plans.txt', 'my-new-bucket', policy)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Download an object to a folder===&lt;br /&gt;
:'''Note:''' ''This downloads the object poetry.pdf and saves it in /home/larry/documents/''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
open('/home/larry/documents/poetry.pdf', 'w') do |file|&lt;br /&gt;
        AWS::S3::S3Object.stream('poetry.pdf', 'my-new-bucket') do |chunk|&lt;br /&gt;
                file.write(chunk)&lt;br /&gt;
        end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Deleting an object===&lt;br /&gt;
:'''Note:''''' This deletes the object goodbye.txt''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AWS::S3::S3Object.delete('goodbye.txt', 'my-new-bucket')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Generating object download urls===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'hello.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :authenticated =&amp;gt; false&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
puts AWS::S3::S3Object.url_for(&lt;br /&gt;
        'secret_plans.txt',&lt;br /&gt;
        'my-new-bucket',&lt;br /&gt;
        :expires_in =&amp;gt; 60 * 60&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''Expected Output:'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/hello.txt&lt;br /&gt;
http://objects.dreamhost.com/my-bucket-name/secret_plans.txt?Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;amp;Expires=1316027075&amp;amp;AWSAccessKeyId=XXXXXXXXXXXXXXXXXXX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
:Source: http://ceph.com/docs/master/radosgw/s3/ruby/&lt;br /&gt;
&lt;br /&gt;
===Upload a file to Amazon S3===&lt;br /&gt;
:As per the Apache License v 2.0, the follow code is reproducible and redistributable  with the following [http://aws.amazon.com/apache-2-0/ license].&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;br /&gt;
#&lt;br /&gt;
# Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;). You&lt;br /&gt;
# may not use this file except in compliance with the License. A copy of&lt;br /&gt;
# the License is located at&lt;br /&gt;
#&lt;br /&gt;
#     http://aws.amazon.com/apache2.0/&lt;br /&gt;
#&lt;br /&gt;
# or in the &amp;quot;license&amp;quot; file accompanying this file. This file is&lt;br /&gt;
# distributed on an &amp;quot;AS IS&amp;quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF&lt;br /&gt;
# ANY KIND, either express or implied. See the License for the specific&lt;br /&gt;
# language governing permissions and limitations under the License.&lt;br /&gt;
&lt;br /&gt;
require 'aws-sdk'&lt;br /&gt;
&lt;br /&gt;
(bucket_name, file_name) = ARGV&lt;br /&gt;
unless bucket_name &amp;amp;&amp;amp; file_name&lt;br /&gt;
  puts &amp;quot;Usage: upload_file.rb &amp;lt;BUCKET_NAME&amp;gt; &amp;lt;FILE_NAME&amp;gt;&amp;quot;&lt;br /&gt;
  exit 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
# get an instance of the S3 interface using the default configuration&lt;br /&gt;
s3 = AWS::S3.new&lt;br /&gt;
&lt;br /&gt;
# create a bucket&lt;br /&gt;
b = s3.buckets.create(bucket_name)&lt;br /&gt;
&lt;br /&gt;
# upload a file&lt;br /&gt;
basename = File.basename(file_name)&lt;br /&gt;
o = b.objects[basename]&lt;br /&gt;
o.write(:file =&amp;gt; file_name)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;Uploaded #{file_name} to:&amp;quot;&lt;br /&gt;
puts o.public_url&lt;br /&gt;
&lt;br /&gt;
# generate a presigned URL&lt;br /&gt;
puts &amp;quot;\nUse this URL to download the file:&amp;quot;&lt;br /&gt;
puts o.url_for(:read)&lt;br /&gt;
&lt;br /&gt;
puts &amp;quot;(press any key to delete the object)&amp;quot;&lt;br /&gt;
$stdin.getc&lt;br /&gt;
&lt;br /&gt;
o.delete&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sramase</name></author>
	</entry>
</feed>