Ruby Tutorial Speedrun

PREFACE:

This is a story about how I accepted an interview with an organization that seemed to think I was a “ruby” (rails presumably?) developer.
Unwilling to disabuse a nice technical recruiter, and with only 1 full day to prepare for the interview…
The product of this extremely hasty exercise in scaffolding scaffolds with scaffolding might still be hosted live at:
https://frozen-ridge-66039.herokuapp.com/microposts
Please don’t break it until at least 4pm pacific time, thank you~!

CHAPTER ONE: HELLO WORLDING

provisioned IDE

[x]

configured remote cloud9 instance for rails

[x]

initializing project

[x]

amended project gemfile

[x] 2021-03-16-1632

bundle update, bundle install, resolved dependencies

[x] 1638

we did it reddit

[x] 1644

Yay! You’re on Rails!  

MVC framework:  
separation of concerns design:  
user is using a Browser, which sends requests  
the webserver passes requests to a Rails Controller.  
    contextually a Controller might render a View,  
    which is some templated thing that gets baked into a chain of HTML delimiters  
    and shot at the user's browser out of a cannon.  
database interacts only with a thing called a model,  
    which is some kind of 'agent' that interacts with the database on the part of the Controller.  

hello worlded

[x] 1702

We're going to make our first diff from the empty-initialized app by adding a Controller Action.  
It will render a string and serve that instead of the default rails page when the server is queried.  

disgusterbigbluster:~/environment/hello_app (master) $ ls app/controllers/*_controller.rb  
app/controllers/application_controller.rb  

In our first exercise we are going to modify an existing controller rather than creating a new controller.  

class ApplicationController < ActionController::Base  
end  

-->  

class ApplicationController < ActionController::Base  
    def hello   
        render html: "what's good?"  
    end  
end  

That's pretty simple.
Now that we have a class definition, we need to "tell Rails to use that action instead of the default page".
This is done by changing the "root route", which determines the page served for requests for the "root url"
The root url is commonly aliased to / ("slash")

config/routes.rb -->  

Rails.application.routes.draw do    
    root 'application#hello'  
end  

And that's it!  
We got to hello world!  

git single time setup steps

[x] 1712

skipping git and heroku tutorial since we already have experience in git and in pushing to production.  

CHAPTER TWO: A TO YAPP

generating a scaffolding up to heaven  

resolved git issues (there’s always git issues)

[x] 1801

pushed empty-initialized repo to sqcu/to_yapp

[x] 1801

wrote another hello world line

[x] 1829

heroku push?

[x] 1922 (dt 53m)

disgusterbigbluster:~/environment/to_yapp (main) $ heroku create 
Creating app... done, ⬢ frozen-ridge-66039
https://frozen-ridge-66039.herokuapp.com/ | https://git.heroku.com/frozen-ridge-66039.git

$ git commit -am "Add hello"  
$ heroku create  
$ git push && git push heroku main  

ok so this doesn't work
our ruby was the wrong version and heroku considers 2.6.3v62 or whatever to be VERY INSECURE

a long debug chain produced:
rvm install 2.6.6
rvm use 2.6.6

Yes, we are now in "copy magic numbers from heroku and command structures from stackoverflow DIRECTLY into the shell"
problem solving mode.  I don't like it.

bundle update
bundle install --without production

very long update

disgusterbigbluster:~/environment/to_yapp (main) $ ruby -v
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-linux]

ok pack it up boys that actually worked
total elapsed time heroku-debugging: 53 minutes
this might rival the total time spent on ruby-related tasks 

take a break, this last step was substantially stressful

[x] 2107

actually ate dinner and did some other stuff instead of just taking a half hour
running close to bedtime, might not work on the twitteric late in the night so thinking about it won't keep me awake

CHAPTER THREE: DATA MODEL AND CRUDDING IT

rise and grind gamers

[x] 2021-03-17-1129

the 'toy' in toe-yapper is that the 'microblog' platform won't have any nonessential features,
such as, for example, user authentication or passwords.  
we'll have a data model for "users" and for "microposts".  

users will have a unique identifier (integer),  
a username (string),  
and an email address (string).  
microposts have an id (int,  
a content field (of type "text"),  
and a user id (int).  

this sounds a lot like a minimal textboard, because it kind of is!  

scaffolding aka “skate fast eat ass development”

[x] 1146

"scaffold" is a command ingested by the "rails generate" script.
the argument for the "scaffold" command is the singular version of resource name (e.g. User),
together with optional params for the data model's attributes.

example of use:  
rails generate scaffold User name:string email:string  
.  
.  
.  
Your Ruby version is 2.6.3, but your Gemfile specified 2.6.6  

instead of approaching this problem in some more complicated way, what if we just tried  
rvm use 2.6.6

and we're golden, scaffolder did its scaffolding!

of note: ruby automatically creates a 'primary key' in the database besides the specified name:string and email:string fields!  
we can (will) just hijack the primary key as our uid for microblog.

database migration

[x] 1149

disgusterbigbluster:~/environment/to_yapp (main) $ rails db:migrate    
== 20210317184501 CreateUsers: migrating ======================================  
-- create_table(:users)  
-> 0.0056s  
== 20210317184501 CreateUsers: migrated (0.0061s) =============================  

configure dev to_yapp server to accept incoming connections

[x] 1151

CRUD trials completed

[x] 1158

the ruby server logging is actually pretty interesting!  

Started POST "/users" for 67.180.169.167 at 2021-03-17 18:58:13 +0000  
Cannot render console from 67.180.169.167! Allowed networks: 127.0.0.0/127.255.255.255, ::1  
Processing by UsersController#create as JS  
Parameters: {"authenticity_token"=>"wxxm9eOLs9n+z7YdpHGvtZdoSvZkuJm9uWRg72jTqxr3dQ9iuUJvZUmAm6yR2kYjMPGDF8bUVpI9crSp5GWE0g==", "user"=>{"name"=>"ronald bruhington II", "email"=>"bruhbruh@example.com"}, "commit"=>"Create User"}  
TRANSACTION (0.1ms)  begin transaction  
↳ app/controllers/users_controller.rb:30:in `block in create'  
User Create (3.2ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "ronald bruhington II"], ["email", "bruhbruh@example.com"], ["created_at", "2021-03-17 18:58:13.773344"], ["updated_at", "2021-03-17 18:58:13.773344"]]  
↳ app/controllers/users_controller.rb:30:in `block in create'  
TRANSACTION (6.3ms)  commit transaction  
↳ app/controllers/users_controller.rb:30:in `block in create'  
Redirected to https://753f368d3e0d41e7bc4b8bc287996e63.vfs.cloud9.us-west-1.amazonaws.com/users/3  
Completed 200 OK in 21ms (ActiveRecord: 9.5ms | Allocations: 4606)  

We get a description of every db transaction we requested by interacting with the server from the html front-end, including the time cost for each transaction.

routing and controllers

[x] 1218

we replaced our old index in routes.rb with  
root 'users#index'  
this ought to change the root page for our server to the users index, I think
it appears that the scaffolded users_controller.rb inherits application_controller.rb.
I would not be surprised if our 'hello' action could be invoked by users_controller!

messed around with some of the controller output strings corresponding to our CRUD actions.
as always, the four elements of traditional mythology are CREATE/POST, READ/GET, UPDATE/PATCH, and DELETE/DELETE.

def index  
  @users = User.all  
end  

the line "@users = User.all" requests the User model to retrieve all users within the database, 
then places them inside the instance variable "@users" where I suppose it is used by the other controller definitions!
instance variables are available to Views by default, which goes pretty far to explain the spooky magic of how the autogenerated CRUD app has so few lines of boilerplate code. 

when we inspect user.rb from our scaffolded code, we see  

class User < ApplicationRecord  
end  

our entire user data model is just inherited from the ApplicationRecord library!
also of note is the complete absence of input validation/sanitation,  
complete absence of authentication,  
complete absence of styling,  
and of course generating this scaffolded code fostered very little understanding of how to write an equivalent web app!  
the scaffolded code is still quite nice for demonstrating the structure of ruby-on-rails projects, and how the resources interact with each other.

microposts

[x] 1229

it's 3 am, time for your code scaffolding!  
	
rails generate scaffold Micropost content:text user_id:integer  
	
disgusterbigbluster:~/environment/to_yapp (main) $ rails db:migrate  
== 20210317192149 CreateMicroposts: migrating =================================  
-- create_table(:microposts)  
    -> 0.0111s  
== 20210317192149 CreateMicroposts: migrated (0.0123s) ========================  

our routes.rb was updated automatically to include a "resources :microposts" entry, how convenient!  
this implies we'll see something if we hit /microposts
and it does!

interestingly, we don't even need to reload the rails server to immediately serve up "/microposts", actually make a micropost, and then view it!

Started POST "/microposts" for 67.180.169.167 at 2021-03-17 19:27:11 +0000  
Cannot render console from 67.180.169.167! Allowed networks: 127.0.0.0/127.255.255.255, ::1  
Processing by MicropostsController#create as JS  
Parameters: {"authenticity_token"=>"8PHnii9sfp8RVI60YhmfKRbb7mLqjSUNO8xK59lPX+wqfep1YhEIxap7V7AYS4eXqsBv86H6GHxunMs5wTmR1g==", "micropost"=>{"content"=>"THIS MUSIC IS PRETTY AGRESSIVE AND MERLY SHOULD BE ONLY LISTENED TO BY THE RESPECT HIMSELF YES THE GOD THE PAST HUMAN THE! \"Lil B\"\n\nTHANK YOU BASEDGOD THANK YOU - Lil B\n", "user_id"=>"1"}, "commit"=>"Create Micropost"}  
TRANSACTION (0.1ms)  begin transaction  
↳ app/controllers/microposts_controller.rb:30:in `block in create'  
Micropost Create (2.0ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "THIS MUSIC IS PRETTY AGRESSIVE AND MERLY SHOULD BE ONLY LISTENED TO BY THE RESPECT HIMSELF YES THE GOD THE PAST HUMAN THE! \"Lil B\"\n\nTHANK YOU BASEDGOD THANK YOU - Lil B\n"], ["user_id", 1], ["created_at", "2021-03-17 19:27:11.581087"], ["updated_at", "2021-03-17 19:27:11.581087"]]  
↳ app/controllers/microposts_controller.rb:30:in `block in create'  
TRANSACTION (7.0ms)  commit transaction  
↳ app/controllers/microposts_controller.rb:30:in `block in create'  
Redirected to https://753f368d3e0d41e7bc4b8bc287996e63.vfs.cloud9.us-west-1.amazonaws.com/microposts/1  
Completed 200 OK in 25ms (ActiveRecord: 9.0ms | Allocations: 4656)  

applying any kind of input validation at all, please I beg you

[x] 1243

this step is pretty direct too!
micropost.rb 
-->
...  
validates :content, length: { maximum:144 }  
...  

oddly: our documentation believes that an autogenerated error message will be rendered in html and shot at the user.
in practice, our validation rule happens silently and no error panel is drawn up for the user :(
double oddly: our website seems to work in the same browser as the AWS cloud9 console, but not in a chrome instance to cross-check this behavior.

data model associations

[x] 1252

user.rb  
-->  
has_many :microposts  

micropost.rb  
-->  
belongs_to :user

they're paired off! so cute!  
using rails console, we can probe the user and see the microposts connected to their uid!

2.6.6 :004 > first_user = User.first  
User Load (0.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]  
    => #<User id: 1, name: "rick stickler", email: "prickler@example.com", created_at: "2021-03-17 18:56:08.583860000 +0000", updated_at: "2021-03-17 18:56:36.406863000 +0000">   
2.6.6 :005 > first_user.microposts  
Micropost Load (0.1ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? /* loading for inspect */ LIMIT ?  [["user_id", 1], ["LIMIT", 11]]  
    => #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 1, content: "THIS MUSIC IS PRETTY AGRESSIVE AND MERLY SHOULD BE...", user_id: 1, created_at: "2021-03-17 19:27:11.581087000 +0000", updated_at: "2021-03-17 19:27:11.581087000 +0000">]>   

micropost = first_user.microposts.first
...
micropost.user
...

this output is pretty robust!

watching heroku slowly ingest the microblog ruby updates

[x] 1259

remote: Verifying deploy... done.  
To https://git.heroku.com/frozen-ridge-66039.git  
    09ae02c..44a3065  main -> main  
-->  	
    We're sorry, but something went wrong.  
If you are the application owner check the logs for more information.  

unsurprisingly, heroku is the weakest link in the cloud9 -> ruby on rails -> heroku production chain.
rolling back to the hello world revision so the heroku server does something instead of nothing at all.  
disappointing.

CHAPTER FOUR: OPAQUE REMOTE HOST DEBUGGING

heroku logs

[x] 1312
$ heroku logs

2021-03-17T19:57:00.014048+00:00 app[web.1]: I, [2021-03-17T19:57:00.013978 #4]  INFO -- : [912839ee-265f-4ab0-b4d6-536928a20974] Completed 500 Internal Server Error in 163ms (ActiveRecord: 82.6ms | Allocations: 5718)   
2021-03-17T19:57:00.016193+00:00 app[web.1]: [912839ee-265f-4ab0-b4d6-536928a20974] ActionView::Template::Error (PG::UndefinedTable: ERROR:  relation "users" does not exist  
2021-03-17T19:57:00.016193+00:00 app[web.1]: LINE 1: SELECT "users".* FROM "users"  
2021-03-17T19:57:00.016194+00:00 app[web.1]: ^  
2021-03-17T19:57:00.016194+00:00 app[web.1]: ):  

heroku run rails db:migrate  
...

add styling

[x] 1327

app/assets/stylesheets/  
+fiftyeightplus.css  

app/view/layouts/  
application.html.erb  
-->
...
    <%= stylesheet_link_tag 'fiftyeightplus.css' %>  
...  

git add .
git commit -m "add styling"
git push && git push heroku main 

wrap it up kids

[x] 1338

pushed this notes document to static site generator
wondered why most of the post is rendered in code blocks
rendered the rest of the post in code blocks :)