Rapid Prototyping with Rails: Lesson 4, part 1

Items Covered

  1. Ajax
  2. Slugs
  3. Simple Admin Role
  4. Time Zones
  5. Exposing APIs

Ajax

There are two forms of Javascript, 1. (UJR) Unobstursive Js - which seperates the behavior layer from the websites content structure and presentation 2. (SJR) Server Generated Responses (The Rails Way)

Ajax is good for reloading only part of a page when all else stays the same. Really helpful when you have an expensive page that has alot of aggregate information. JQuery sits on top of Javascript to resolve the browser-specific qwerks

An example of an Ajax request in jQuery code:
    $(document).ready(function() {
      $('#hit_form input').click(function() { ** 1. Unobstrusive javascript event listener
        $.ajax({** 2. Trigger ajax  request
        type: 'POST'
        url: 'player/hit'
        data: {param1: "hi", param2: "There"}
      }).done(function(msg) { ** 3. Handle the Response
        $('#some_element').html(msg);
      })
    });
  )};

So the steps to an ajax request are: 1. Unobstrusive Javascript Event Listener 2. Trigger ajax request 3. Handle the response

Step 1. Unobstrusive Javascript Event Listener

  1. To add the ajax call to your up vote in your postit app, add remote: true: <%= linkto votepost_path(post, vote:'true'), method: 'post', remote: true do %> <% end %> <% end %>

*This will add a data-remote="true", similar to the data-method="post" so similarly, just as with the data-method='post' looks for data-method and applies javascript that turns the anchor tag into 'get' link to 'post' form, the same occurs when remote: true is identified, it turns those anchor tags into an ajax call(as seen above)

In terminal, when clicking the up link, you should see: Processing by PostsController#vote as JS, but normally its as html, this let's you know that its an ajax call.

Step 2. Trigger ajax request

We have to be able to handle this response in the PostsController#vote: 2. We have add code to handle the js request in vote controller action:

def vote
    vote = Vote.create(voteable: @post, creator: current_user, vote: params[:vote])

    respond_to do |format|
      format.html do
        if vote.valid?
          flash[:notice] = "Your vote was counted!"
        else
          flash[:error] = "Your vote was <strong>not</strong> recorded!".html_safe
        end
        redirect_to :back
      end
      format.js
    end
  end

We add format.js becasue instead of adding unobstrusive js, format.js will cause rails to render a js.erb template under the same name as the controller action name. The method determines if it can take a block. You can only render a template and redirect_to a url, the default is to render a template

Step 3. Testing out vote.js.erb

#posts/vote.js.erb
** You have access to the instance variables created in the action

alert('total votes for <%= @post.title %> is <%= @post.total_votes %>');

The above action creates a pop up alert but does not change the number of votes on the main page. When inspecting the element, it shows that this is just an empty span in the html. Js needs away to identify the empty span to change to the number, that is accomplished through an html id class:

Step 4. Changing the number of votes

#posts/_post.html.erb

<span id='post_<%=post.id%>_votes'><%= post.total_votes %></span>

Rails gives you the ability to use js and parse out active record objects which isnt possible with normal js. So now, we can update the vote.js.erb file:

$('#post_<%= @post.id %>'_votes).html ('<%= post.total_votes %>');

You can now also add remote: true to the down vote also.

Step 5. Limiting the number of votes

So when add the ajax request, we now do not get an error if we try to vote on a post we've already voted on. 5a) We need to turn the local variable 'vote' into an instance variable under the vote action:

def vote
    @vote = Vote.create(voteable: @post, creator: current_user, vote: params[:vote])

    respond_to do |format|
      format.html do
        if vote.valid?
          flash[:notice] = "Your vote was counted!"
        else
          flash[:error] = "Your vote was <strong>not</strong> recorded!".html_safe
        end
        redirect_to :back
      end
      format.js
    end
  end

5b) Write an if statement in the vote.js.erb file:

<% if @vote.valid? %>
      $("#post_<%= @post.id %>_votes").html("<%= @post.total_votes %> votes")
    <% else %>
      alert("You can only vote on a post once.");
    <% end %>

So in summary, Rails Core Developers wrote jQuery library that converts remote= true into data-remote= true, which converts to an ajax request. In turn, we told ajax how to respond via html and js

Rapid Prototyping with Rails: Lesson 3, Working with has_secured_password

Steps:

  1. Install bcrypt-ruby gem
  2. Add password_digest column to users table
  3. Add hassecuredpassword to user model
  4. Turned off validations for hassecuredpassword

Creating password in console:

  1. bob = User.first
  2. bob.password = "password"
  3. bob.password_confirmation = "password"
  4. bob.save

To check what password is in console:

You can never retrieve the password directly, but you can verify using the authenticate

bob.authenticate('password')
  • will return False, if guess is incorrect or retrieve the user object if True.

Password Digest column includes salts to prevent against rainbow attacks. Salts adds a small chunk of random data to password to prevent those attacks.

Rapid Prototyping with Rails: Lesson 3, Authentication

Steps

Step 1: Create routes

#routes.rb
add sessions#new, sessions#create, sessions#destory routes

Step 2: Create sessions template

#sessions/new.html.erb
Add html

Step 3: Sessions_Controller.rb

class SessionsController < ApplicationController
  def create
  user = User.where(username: params[:username]).first
    or
  user = User.find_by(username: params[:username])

Alternative Flash syntax

  flash.now[:error] = "There is something wrong with your username or password."
  render :new
  end
end

Step 4: Helpers

#application_helper.rb
  1. create current_user and logged_in? methods

* Memoization: allows you to only hit the database once when being called multiple times on a template

  2. add helper_method syntax to make accessible in views

Step 5. _navigation.html.erb

Two ways to protect the fuctionality of your application for non-logged in users: 1. Links on User Interface (using 'if loggedin? method') 2. Urls/Controller actions (using beforeaction)

We want to keep those who aren't logged in from creating a post.

<% if logged_in? %>
<div class='nav item'>
  <%= link_to "New Post", new_post_path, class: 'btn btn-success btn-small' %>
</div>
<% end %>

Step 6. Add before action to prevent navigation to certain links

posts_controller.rb
  add before_action :require_user, except: [:index, :show]

Step 7. require_user method

Create require_user method in application_controller.rb

Step 8. Add current_user

Remove User.first and add current_user for post.creator and comment.creator

Rapid Prototyping with Rails: Lesson 3, Feature Building

Review of Building Out a Feature

  1. Bulid out html link in parital or html.erb
  2. Build necessary routes
    • run grep routes to determine which routes are needed
  3. Write code for action in controller
    • run binding pry to see what parameters are being submitted

Rapid Prototyping with Rails: Lesson 3, HTTP

HTTP has two parts:

1. Request:

  • Verb/Method: GET, POST
  • URL
  • Parameters

2. Response:

  1. Status Code
    • 200 Ok
    • 302 Redirect (issues another request)
    • 404 File Not Found
    • 500 Application Error
  2. Payload/Message/Body - which will depend on the request

Modern browsers will block against redirect loops and/or limit redirects.

A request is not connected to another request - meaning its stateless.

An example:
GET/new_game
  - display the form to enter your name
  - render a view: 200 and HTML (complete the response)

POST/new_game
  - save the name somewhere (persistence layer)
  - display the next thing
  - redirect to another URL: 302 and the next URL completes the response.

Persistency Layer
1. Database (most common)
2. Session cookies (persistency within your browser)