diff --git a/source/app/controllers/application_controller.rb b/source/app/controllers/application_controller.rb index d83690e..99ee3ea 100644 --- a/source/app/controllers/application_controller.rb +++ b/source/app/controllers/application_controller.rb @@ -2,4 +2,7 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + + def index + end end diff --git a/source/app/controllers/urls_controller.rb b/source/app/controllers/urls_controller.rb index ef26710..0151246 100644 --- a/source/app/controllers/urls_controller.rb +++ b/source/app/controllers/urls_controller.rb @@ -1,2 +1,50 @@ class UrlsController < ApplicationController + def index + @urls = Url.all + end + + def new + @url = Url.new + end + + def create + @url = Url.new(url_params) + + if @url.save + redirect_to @url + else + render 'new' + end + end + + def show + @url = Url.find(params[:id]) + end + + def edit + @url = Url.find(params[:id]) + end + + def destroy + @url = Url.find(params[:id]) + @url.destroy + + redirect_to urls_path + end + + def jump + url = Url.find_by_short_url(params[:key]) + + if url.nil? + redirect_to root_path + else + url.increment!(:click_count) + redirect_to url.long_url + end + end + + private + def url_params + params.require(:url).permit(:long_url) + end end diff --git a/source/app/models/url.rb b/source/app/models/url.rb new file mode 100644 index 0000000..1a4cce4 --- /dev/null +++ b/source/app/models/url.rb @@ -0,0 +1,36 @@ +require 'uri' +require 'net/http' + +class Url < ActiveRecord::Base + validate :long_url_must_be_valid_uri, :long_url_must_be_reachable + validates :long_url, presence: true + before_save :shorten_url + + private + def shorten_url + range = [*'0'..'9',*'A'..'Z',*'a'..'z'] + self.short_url = Array.new(6){ range.sample }.join if self.short_url.nil? + end + + def long_url_must_be_valid_uri + return if long_url.empty? + + unless long_url =~ /\A#{URI.regexp(['http', 'https'])}\z/ + errors.add(:long_url, "must be a valid url prefaced with http(s)://") + end + end + + def long_url_must_be_reachable + return if long_url.empty? + + url = URI.parse(long_url) + http = Net::HTTP.new(url.host, url.port) + http.read_timeout = 1 + http.start { |http| + http.get(url) + } + + rescue + errors.add(:long_url, "must be a reachable url") + end +end diff --git a/source/app/views/application/index.html.erb b/source/app/views/application/index.html.erb new file mode 100644 index 0000000..1e4e6c0 --- /dev/null +++ b/source/app/views/application/index.html.erb @@ -0,0 +1,4 @@ +

URL Shortener Home

+ +<%= link_to 'New Url', new_url_path %>
+<%= link_to 'All Urls', urls_path %> \ No newline at end of file diff --git a/source/app/views/urls/edit.html.erb b/source/app/views/urls/edit.html.erb new file mode 100644 index 0000000..57352a1 --- /dev/null +++ b/source/app/views/urls/edit.html.erb @@ -0,0 +1,3 @@ +

Editing a Url

+ +<%= link_to 'Back', urls_path %> \ No newline at end of file diff --git a/source/app/views/urls/index.html.erb b/source/app/views/urls/index.html.erb new file mode 100644 index 0000000..d150a87 --- /dev/null +++ b/source/app/views/urls/index.html.erb @@ -0,0 +1,23 @@ +

Listing Urls:

+ + + + + + + + + <% @urls.each do |url| %> + + + + + + + + + <% end %> +
Short UrlTimes VisitedOriginal Url
<%= url.short_url %><%= url.click_count %><%= url.long_url %><%= link_to 'Show', url_path(url) %><%= link_to 'Edit', edit_url_path(url) %><%= link_to 'Delete', url_path(url), method: :delete, data: {confirm: 'Are you sure?'} %>
+ +<%= link_to 'New Url', new_url_path %>
+<%= link_to 'Home', root_path %> \ No newline at end of file diff --git a/source/app/views/urls/new.html.erb b/source/app/views/urls/new.html.erb new file mode 100644 index 0000000..16104bd --- /dev/null +++ b/source/app/views/urls/new.html.erb @@ -0,0 +1,27 @@ +

Make a new url here

+ +<%= form_for :url, url: urls_path, local: true do |form| %> + <% if @url.errors.any? %> +
+

+ <%= pluralize(@url.errors.count, "error") %> prohibited this url from being saved: +

+ +
+ <% end %> + +

+ <%= form.label :long_url %> + <%= form.text_field :long_url %> +

+ +

+ <%= form.submit %> +

+<% end %> + +<%= link_to 'Home', root_path %> \ No newline at end of file diff --git a/source/app/views/urls/show.html.erb b/source/app/views/urls/show.html.erb new file mode 100644 index 0000000..ac0037f --- /dev/null +++ b/source/app/views/urls/show.html.erb @@ -0,0 +1,18 @@ +

Showing a URL here

+

+ Original Url: + <%= @url.long_url %> +

+ +

+ Visit Count: + <%= @url.click_count %> +

+ +

+ Short Url: + <%= @url.short_url %> +

+ +<%= link_to 'Back', urls_path %>
+<%= link_to 'Home', root_path %> diff --git a/source/config/routes.rb b/source/config/routes.rb index 3f66539..d02b98d 100644 --- a/source/config/routes.rb +++ b/source/config/routes.rb @@ -53,4 +53,10 @@ # # (app/controllers/admin/products_controller.rb) # resources :products # end + # + + get 'application/index' + resources :urls + get '/:key' => 'urls#jump' + root 'application#index' end diff --git a/source/db/migrate/20180123203210_create_urls.rb b/source/db/migrate/20180123203210_create_urls.rb new file mode 100644 index 0000000..7c172a8 --- /dev/null +++ b/source/db/migrate/20180123203210_create_urls.rb @@ -0,0 +1,8 @@ +class CreateUrls < ActiveRecord::Migration + def change + create_table :urls do |t| + + t.timestamps + end + end +end diff --git a/source/db/migrate/20180123215003_add_long_url_to_url.rb b/source/db/migrate/20180123215003_add_long_url_to_url.rb new file mode 100644 index 0000000..9d890a9 --- /dev/null +++ b/source/db/migrate/20180123215003_add_long_url_to_url.rb @@ -0,0 +1,5 @@ +class AddLongUrlToUrl < ActiveRecord::Migration + def change + add_column :urls, :long_url, :text + end +end diff --git a/source/db/migrate/20180124143738_add_short_url_to_url.rb b/source/db/migrate/20180124143738_add_short_url_to_url.rb new file mode 100644 index 0000000..5885fcd --- /dev/null +++ b/source/db/migrate/20180124143738_add_short_url_to_url.rb @@ -0,0 +1,5 @@ +class AddShortUrlToUrl < ActiveRecord::Migration + def change + add_column :urls, :short_url, :text + end +end diff --git a/source/db/migrate/20180124160940_add_count_to_url.rb b/source/db/migrate/20180124160940_add_count_to_url.rb new file mode 100644 index 0000000..8582ba8 --- /dev/null +++ b/source/db/migrate/20180124160940_add_count_to_url.rb @@ -0,0 +1,5 @@ +class AddCountToUrl < ActiveRecord::Migration + def change + add_column :urls, :click_count, :integer, default: 0 + end +end diff --git a/source/db/schema.rb b/source/db/schema.rb new file mode 100644 index 0000000..a4ed327 --- /dev/null +++ b/source/db/schema.rb @@ -0,0 +1,24 @@ +# 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: 20180124160940) do + + create_table "urls", force: true do |t| + t.datetime "created_at" + t.datetime "updated_at" + t.text "long_url" + t.text "short_url" + t.integer "click_count", default: 0 + end + +end