diff --git a/source/Gemfile b/source/Gemfile index 9627b8b..963dc97 100644 --- a/source/Gemfile +++ b/source/Gemfile @@ -13,6 +13,7 @@ gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' # See https://github.com/sstephenson/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby +gem 'bootstrap-sass' # Use jquery as the JavaScript library gem 'jquery-rails' @@ -22,6 +23,7 @@ gem 'turbolinks' gem 'jbuilder', '~> 2.0' # bundle exec rake doc:rails generates the API under doc/api. gem 'sdoc', '~> 0.4.0', group: :doc +gem 'haml', group: :development # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring', group: :development @@ -38,4 +40,3 @@ gem 'spring', group: :development # Use debugger # gem 'debugger', group: [:development, :test] gem 'rspec-rails', group: [:development, :test] - diff --git a/source/Gemfile.lock b/source/Gemfile.lock index fcf8b98..9efd4a6 100644 --- a/source/Gemfile.lock +++ b/source/Gemfile.lock @@ -28,6 +28,11 @@ GEM thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) + autoprefixer-rails (6.3.6.2) + execjs + bootstrap-sass (3.3.5) + autoprefixer-rails (>= 5.0.0.1) + sass (>= 3.2.19) builder (3.2.2) coffee-rails (4.0.1) coffee-script (>= 2.2.0) @@ -39,6 +44,8 @@ GEM diff-lcs (1.2.5) erubis (2.7.0) execjs (2.2.1) + haml (4.0.6) + tilt hike (1.2.3) i18n (0.6.11) jbuilder (2.2.2) @@ -125,7 +132,9 @@ PLATFORMS ruby DEPENDENCIES + bootstrap-sass coffee-rails (~> 4.0.0) + haml jbuilder (~> 2.0) jquery-rails rails (= 4.1.6) @@ -136,3 +145,6 @@ DEPENDENCIES sqlite3 turbolinks uglifier (>= 1.3.0) + +BUNDLED WITH + 1.12.5 diff --git a/source/app/assets/stylesheets/application.css b/source/app/assets/stylesheets/application.scss similarity index 89% rename from source/app/assets/stylesheets/application.css rename to source/app/assets/stylesheets/application.scss index a443db3..cfb0ca8 100644 --- a/source/app/assets/stylesheets/application.css +++ b/source/app/assets/stylesheets/application.scss @@ -10,6 +10,8 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * - *= require_tree . - *= require_self + */ +@import "bootstrap-sprockets"; +@import "bootstrap"; +@import "urls.css.scss"; diff --git a/source/app/assets/stylesheets/urls.css.scss b/source/app/assets/stylesheets/urls.css.scss index a4281ec..b2ada52 100644 --- a/source/app/assets/stylesheets/urls.css.scss +++ b/source/app/assets/stylesheets/urls.css.scss @@ -1,3 +1,12 @@ // 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/ +body { + text-align: center; +} + +.form-group { + width: 50%; + margin-left: 25%; + margin-right: 25%; +} diff --git a/source/app/controllers/urls_controller.rb b/source/app/controllers/urls_controller.rb index ef26710..d0d24d9 100644 --- a/source/app/controllers/urls_controller.rb +++ b/source/app/controllers/urls_controller.rb @@ -1,2 +1,33 @@ class UrlsController < ApplicationController + #require 'socket' + skip_before_action :verify_authenticity_token + + def new + @url = Url.new + end + + def create + @url = Url.create(url_params) + if @url.errors.any? + @url.address = "" + errors = "" + @url.errors.full_messages.each { |msg| errors += msg + " " } + p errors + redirect_to root_path, alert: errors + else + redirect_to root_path, notice: "Your URL: http://#{request.host_with_port}/#{@url.shortcode}" + end + end + + def get + @url = Url.find_by(:shortcode => params[:id]) + @url.click_count += 1 + @url.save + redirect_to @url.address + end + + private + def url_params + params.require(:url).permit(:address) + end end diff --git a/source/app/models/url.rb b/source/app/models/url.rb new file mode 100644 index 0000000..af8a77f --- /dev/null +++ b/source/app/models/url.rb @@ -0,0 +1,37 @@ +require 'digest/sha1' +require 'uri' + +class Url < ActiveRecord::Base + before_validation :smart_url_protocol + before_create :set_shortcode + validate :is_url, on: :create + + protected + + def set_shortcode + full = Digest::SHA1.hexdigest(self.address) + start = 0 + code = full[start..(start+5)] + loop do + break if !Url.find_by(:shortcode => code) || (start + 5 >= full.length) + start += 1 + code = full[start..(start+5)] + end + self.shortcode = code + end + + def is_url + errors.add(:address, "is not a valid URL") unless !!URI.parse(address) + rescue URI::InvalidURIError + errors.add(:address, "is not a valid URL") + end + + def smart_url_protocol + unless self.address[/\Ahttp:\/\//] || self.address[/\Ahttps:\/\//] + self.address = "http://#{self.address}" + end + end + + + +end diff --git a/source/app/views/urls/new.haml b/source/app/views/urls/new.haml new file mode 100644 index 0000000..1a26fe0 --- /dev/null +++ b/source/app/views/urls/new.haml @@ -0,0 +1,20 @@ +%h1 Jonah's Fantastic URL Shortener + +- if flash[:notice] && !@url.errors.any? + .notice + = flash[:notice] +- if flash[:alert] + .alert + = flash[:alert] + += form_for @url do |u| + - if @url.errors.any? + .alert.alert-error + - @url.errors.full_messages.each do |msg| + %strong + = msg + .form-group + = u.label :address, "Enter the address to shorten:" + = u.text_field :address, class: "form-control" + .form-group + = u.submit "Submit", class: "btn btn-submit" diff --git a/source/config/routes.rb b/source/config/routes.rb index 3f66539..21812d7 100644 --- a/source/config/routes.rb +++ b/source/config/routes.rb @@ -1,4 +1,9 @@ Rails.application.routes.draw do + + root 'urls#new' + resources :urls + get ':id' => 'urls#get' + # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/source/db/migrate/20160531190449_create_urls.rb b/source/db/migrate/20160531190449_create_urls.rb new file mode 100644 index 0000000..03a3fb7 --- /dev/null +++ b/source/db/migrate/20160531190449_create_urls.rb @@ -0,0 +1,10 @@ +class CreateUrls < ActiveRecord::Migration + def change + create_table :urls do |t| + t.string :address + t.string :shortcode + + t.timestamps + end + end +end diff --git a/source/db/migrate/20160531200238_add_click_count_to_url.rb b/source/db/migrate/20160531200238_add_click_count_to_url.rb new file mode 100644 index 0000000..3e6efc8 --- /dev/null +++ b/source/db/migrate/20160531200238_add_click_count_to_url.rb @@ -0,0 +1,5 @@ +class AddClickCountToUrl < 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..564c43c --- /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: 20160531200238) do + + create_table "urls", force: true do |t| + t.string "address" + t.string "shortcode" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "click_count", default: 0 + end + +end diff --git a/source/spec/models/url_spec.rb b/source/spec/models/url_spec.rb new file mode 100644 index 0000000..209ca4c --- /dev/null +++ b/source/spec/models/url_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Url, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end