In a previous assignment you created a simple Web app that plays the Wordguesser game.
More specifically:
-
You wrote the app's code in its own class,
WordGuesserGame
, which knows nothing about being part of a Web app. -
You used the Sinatra framework to "wrap" the game code by providing a set of RESTful actions that the player can take, with the following routes:
GET /new
-- default ("home") screen that allows player to start new gamePOST /create
-- actually creates the new gameGET /show
-- show current game status and let player enter a movePOST /guess
-- player submits a letter guessGET /win
-- redirected here whenshow
action detects game wonGET /lose
-- redirected here whenshow
action detects game lost
-
To maintain the state of the game between (stateless) HTTP requests, you stored a copy of the
WordGuesserGame
instance itself in thesession[]
hash provided by Sinatra, which is an abstraction for storing information in cookies passed back and forth between the app and the player's browser.
In this assignment, you'll reuse the same game code but "wrap" it in a simple Rails app instead of Sinatra.
Understand the differences between how Rails and Sinatra handle various aspects of constructing SaaS, including:
- how routes are defined and mapped to actions;
- the directory structure used by each framework;
- how an app is started and stopped;
- how the app's behavior can be inspected by looking at logs or invoking a debugger.
NOTE: You may find these Rails guides and the Rails reference documentation helpful to have on hand.
Like substantially all Rails apps, you can get this one running by doing these steps:
-
Clone or fork the repo
-
Change into the app's root directory
hw-rails-wordguesser
-
Run
bundle install --without production
-
Local Development Codio Run rails server
to start the serverRun rails server -b 0.0.0.0
to start the server
Use the Preview button that says "Project Index" in the top tool bar. Click the drop down and select "Box URL"
For subsequent previews, you will not need to press the drop down -- your button should now read "Box URL".
Q1.1. What is the goal of running bundle install
?
- Install all gems to the system that list in the Gemfile.
Q1.2. Why is it good practice to specify
--without production
when running it on your development computer? - decrease dependencies that unnecessary in project Q1.3. (For most Rails apps you'd also have to create and seed the development database, but like the Sinatra app, this app doesn't use a database at all.)
- Both of this didn't use database. But still can run rails server. Play around with the game to convince yourself it works the same as the Sinatra version.
Both apps have similar structure: the user triggers an action on a game via an HTTP request; a particular chunk of code is called to "handle" the request as appropriate; the WordGuesserGame
class logic is called to handle the action; and usually, a view is rendered to show the result. But the locations of the code corresponding to each of these tasks is slightly different between Sinatra and Rails.
Q2.1. Where in the Rails app directory structure is the code corresponding to the WordGuesserGame
model?
- In models/word_guesser_game.rb
Q2.2. In what file is the code that most closely corresponds to the logic in the Sinatra apps'
app.rb
file that handles incoming user actions? - In app/controllers/game_controlller.rb Q2.3. What class contains that code?
- class Gamecontroller Q2.4. From what other class (which is part of the Rails framework) does that class inherit?
- Inherit from class ApplicationController
Q2.5. In what directory is the code corresponding to the Sinatra app's views (
new.erb
,show.erb
, etc.)? - In app//views
Q2.6. The filename suffixes for these views are different in Rails than they were in the Sinatra app. What information does the rightmost suffix of the filename (e.g.: in
foobar.abc.xyz
, the suffix.xyz
) tell you about the file contents? - .erb is "Embedded RuBy". A .html.erb file is HTML with Ruby code embedded in. Rails will evaluate the Ruby to add content to the file dynamically, and output a pure HTML file for rendering. Q2.7. What information does the other suffix tell you about what Rails is being asked to do with the file?
- Tell us about usability of that file such as .html contain the structure a web page and its content.
Q2.8. In what file is the information in the Rails app that maps routes (e.g.
GET /new
) to controller actions? - In config/routes.rb
Q2.9. What is the role of the
:as => 'name'
option in the route declarations ofconfig/routes.rb
? (Hint: look at the views.) - :as => 'name' using for create link's name to called in views
Both apps ensure that the current game is loaded from the session before any controller action occurs, and that the (possibly modified) current game is replaced in the session after each action completes.
Q3.1. In the Sinatra version, before do...end
and after do...end
blocks are used for session management. What is the closest equivalent in this Rails app, and in what file do we find the code that does it?
- The closest equivalant is before_action :get_game_from_session and after_action :store_game_in_session which found in game_controller.
Q3.2. A popular serialization format for exchanging data between Web apps is JSON. Why wouldn't it work to use JSON instead of YAML? (Hint: try replacing YAML.load()
with JSON.parse()
and .to_yaml
with .to_json
to do this test. You will have to clear out your cookies associated with localhost:3000
, or restart your browser with a new Incognito/Private Browsing window, in order to clear out the session[]
. Based on the error messages you get when trying to use JSON serialization, you should be able to explain why YAML serialization works in this case but JSON doesn't.)
- JSON might doesn't work because the restrictions to serialize or deserialize objects which has circular reference that YMAL supported.
Q4.1. In the Sinatra version, each controller action ends with either redirect
(which as you can see becomes redirect_to
in Rails) to redirect the player to another action, or erb
to render a view. Why are there no explicit calls corresponding to erb
in the Rails version? (Hint: Based on the code in the app, can you discern the Convention-over-Configuration rule that is at work here?)
- Because the Convention-over-Configuration, There isn't required to specify .erb clearly because Rails will render according to the controller's action name.
Q4.2. In the Sinatra version, we directly coded an HTML form using the
<form>
tag, whereas in the Rails version we are using a Rails methodform_tag
, even though it would be perfectly legal to use raw HTML<form>
tags in Rails. Can you think of a reason Rails might introduce this "level of indirection"? - Using form_tag in Rails help us to managed the form data efficiently Q4.3. How are form elements such as text fields and buttons handled in Rails? (Again, raw HTML would be legal, but what's the motivation behind the way Rails does it?)
- Rails using helps such as text_field_tag and button_tag for managed form elements for perspicuously and conveniently.
Q4.4. In the Sinatra version, the
show
,win
andlose
views re-use the code in thenew
view that offers a button for starting a new game. What Rails mechanism allows those views to be re-used in the Rails version? - In Rails, the system that allows views to be reused is Partial Views which we can create partial view by using underscore (_) in front of file's name such _abc.html.erb
The Cucumber scenarios and step definitions (everything under features/
, including the support for Webmock in webmock.rb
) was copied verbatim from the Sinatra version, with one exception: the features/support/env.rb
file is simpler because the cucumber-rails
gem automatically does some of the things we had to do explicitly in that file for the Sinatra version.
Verify the Cucumber scenarios run and pass by running rake cucumber
.
Q5.1. What is a qualitative explanation for why the Cucumber scenarios and step definitions didn't need to be modified at all to work equally well with the Sinatra or Rails versions of the app?
- The abstraction provided by Cucumber's Gherkin language allows scenarios and step definitions to remain unchanged because they focus on high-level user interactions rather than specific implementation details. Both the Sinatra and Rails versions adhere to the same behavior specified in the scenarios, ensuring compatibility without modification.