Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions source/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp

# Ignore vim tempfiles
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you haven't already, you may want to create a global .gitignore for stuff like vim tempfiles & .DS_Store...

See: https://help.github.com/articles/ignoring-files/

*.swo
*.swp
69 changes: 69 additions & 0 deletions source/app/assets/stylesheets/scaffolds.css.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
body {
background-color: #fff;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}

p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}

pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}

a {
color: #000;
&:visited {
color: #666;
}
&:hover {
color: #fff;
background-color: #000;
}
}

div {
&.field, &.actions {
margin-bottom: 10px;
}
}

#notice {
color: green;
}

.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}

#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px;
padding-bottom: 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
margin-bottom: 0px;
background-color: #c00;
color: #fff;
}
ul li {
font-size: 12px;
list-style: square;
}
}
13 changes: 12 additions & 1 deletion source/app/assets/stylesheets/urls.css.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
// Place all the styles related to the Urls controller here.
// Place all the styles related to the urls controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

.urls {
table {
border-collapse: collapse;
tr {
td {
padding: 1em;
}
}
}
}
79 changes: 79 additions & 0 deletions source/app/controllers/urls_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,81 @@
class UrlsController < ApplicationController
before_action :set_url, only: [:show, :edit, :update, :destroy]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another way to do this is to set the callback in the ApplicationController and use skip_before_action here


# GET /urls
# GET /urls.json
def index
@urls = Url.all
end

# GET /urls/1
# GET /urls/1.json
def show
end

# GET /urls/new
def new
@url = Url.new
end

# GET /urls/1/edit
def edit
end

def goto
id = Url.decode_shortcode params[:shortcode]
url = Url.find id
url.click_count += 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this works here, but we normally try to push this logic into the model if possible. for example...

class Url
  def increment
    self.click_count += 1
    save!
  end
end

url.save!
redirect_to url.destination
end
# POST /urls
# POST /urls.json
def create
@url = Url.new(url_params)

respond_to do |format|
if @url.save
format.html { redirect_to @url, notice: 'Url was successfully created.' }
format.json { render :show, status: :created, location: @url }
else
format.html { render :new }
format.json { render json: @url.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /urls/1
# PATCH/PUT /urls/1.json
def update
respond_to do |format|
if @url.update(url_params)
format.html { redirect_to @url, notice: 'Url was successfully updated.' }
format.json { render :show, status: :ok, location: @url }
else
format.html { render :edit }
format.json { render json: @url.errors, status: :unprocessable_entity }
end
end
end

# DELETE /urls/1
# DELETE /urls/1.json
def destroy
@url.destroy
respond_to do |format|
format.html { redirect_to urls_url, notice: 'Url was successfully destroyed.' }
format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_url
@url = Url.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def url_params
params.require(:url).permit(:shortcode, :destination)
end
end
1 change: 1 addition & 0 deletions source/app/helpers/urls_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
module UrlsHelper

end
22 changes: 22 additions & 0 deletions source/app/models/url.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

require 'socket'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???


class Url < ActiveRecord::Base
validates :destination, url: true

before_validation do
self.destination = "http://#{self.destination}" unless /^[a-z]+:/ =~ self.destination
end

def shortcode
id.to_s(36)
end

def self.decode_shortcode shortcode
shortcode.to_i(36)
end

def shortlink
"http://localhost:3000/#{shortcode}"
end
end
24 changes: 24 additions & 0 deletions source/app/validators/url_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

require 'net/http'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. very robust 🐙


class UrlValidator < ActiveModel::EachValidator

def validate_each(record, attribute, value)
uri = URI(value)
return record.errors.add attribute, "must use HTTP or HTTPS" unless ['http','https'].member? uri.scheme
begin
page_checker = Net::HTTP.new uri.host, uri.port
page_checker.use_ssl = uri.scheme.eql? "https"
page_checker.start do |http|
response = http.head (uri.path.empty? ? "/" : uri.path)
puts response.inspect
return record.errors.add attribute, "is not a valid address according to their server" unless response.code.to_i < 400
end
rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
return record.errors.add attribute, "could not be reached for validation"
end
rescue URI::InvalidURIError
record.errors[attribute] = "does not seem to be a valid URL"
end

end
2 changes: 1 addition & 1 deletion source/app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<body class='<%= controller.controller_name %>'>

<%= yield %>

Expand Down
21 changes: 21 additions & 0 deletions source/app/views/urls/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<%= form_for(@url) do |f| %>
<% if @url.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@url.errors.count, "error") %> prohibited this url from being saved:</h2>

<ul>
<% @url.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :destination %><br>
<%= f.text_field :destination %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
6 changes: 6 additions & 0 deletions source/app/views/urls/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>Editing url</h1>

<%= render 'form' %>

<%= link_to 'Show', @url %> |
<%= link_to 'Back', urls_path %>
29 changes: 29 additions & 0 deletions source/app/views/urls/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<h1>Listing urls</h1>

<table>
<thead>
<tr>
<th>Shortcode</th>
<th>Clicks</th>
<th>Destination</th>
<th colspan="3"></th>
</tr>
</thead>

<tbody>
<% @urls.each do |url| %>
<tr>
<td><%= url.shortcode %></td>
<td><%= url.click_count %></td>
<td><%= link_to url.destination, url.destination %></td>
<td><%= link_to 'Show', url %></td>
<td><%= link_to 'Edit', edit_url_path(url) %></td>
<td><%= link_to 'Destroy', url, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>

<br>

<%= link_to 'New Url', new_url_path %>
4 changes: 4 additions & 0 deletions source/app/views/urls/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
json.array!(@urls) do |url|
json.extract! url, :id, :shortcode, :destination
json.url url_url(url, format: :json)
end
5 changes: 5 additions & 0 deletions source/app/views/urls/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1>New url</h1>

<%= render 'form' %>

<%= link_to 'Back', urls_path %>
19 changes: 19 additions & 0 deletions source/app/views/urls/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<p id="notice"><%= notice %></p>

<p>
<strong>Destination:</strong>
<%= link_to @url.destination, @url.destination %>
</p>

<p>
<strong>Shortenened URL:</strong>
<%= link_to @url.shortlink, @url.shortlink %>
</p>

<p>
<strong>Clicks:</strong>
<%= @url.click_count %>
</p>

<%= link_to 'Edit', edit_url_path(@url) %> |
<%= link_to 'Back', urls_path %>
1 change: 1 addition & 0 deletions source/app/views/urls/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.extract! @url, :id, :shortcode, :destination, :created_at, :updated_at
1 change: 1 addition & 0 deletions source/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

module Source
class Application < Rails::Application
config.autoload_paths += %W["#{config.root}/app/validators/"]
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
Expand Down
3 changes: 3 additions & 0 deletions source/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Rails.application.routes.draw do
resources :urls
get ':shortcode' => 'urls#goto'

# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

Expand Down
10 changes: 10 additions & 0 deletions source/db/migrate/20150126180838_create_urls.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateUrls < ActiveRecord::Migration
def change
create_table :urls do |t|
t.string :shortcode
t.string :destination

t.timestamps
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RemoveShortcodeFromUrls < ActiveRecord::Migration
def change
remove_column :urls, :shortcode, :string
end
end
5 changes: 5 additions & 0 deletions source/db/migrate/20150127175240_add_count_to_urls.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddCountToUrls < ActiveRecord::Migration
def change
add_column :urls, :click_count, :integer, default: 0
end
end
23 changes: 23 additions & 0 deletions source/db/schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20150127175240) do

create_table "urls", force: true do |t|
t.string "destination"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "click_count", default: 0
end

end
Loading