diff --git a/source/Gemfile b/source/Gemfile index 9627b8b..a2c043e 100644 --- a/source/Gemfile +++ b/source/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' - +gem 'httparty', '~> 0.13.5' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.1.6' # Use sqlite3 as the database for Active Record @@ -35,7 +35,7 @@ gem 'spring', group: :development # Use Capistrano for deployment # gem 'capistrano-rails', group: :development -# Use debugger -# gem 'debugger', group: [:development, :test] +gem 'pry', group: [:development, :test] +gem 'pry-rails', group: [:development, :test] gem 'rspec-rails', group: [:development, :test] diff --git a/source/Gemfile.lock b/source/Gemfile.lock index fcf8b98..416b1ff 100644 --- a/source/Gemfile.lock +++ b/source/Gemfile.lock @@ -29,6 +29,7 @@ GEM tzinfo (~> 1.1) arel (5.0.1.20140414130214) builder (3.2.2) + coderay (1.1.0) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -40,6 +41,9 @@ GEM erubis (2.7.0) execjs (2.2.1) hike (1.2.3) + httparty (0.13.5) + json (~> 1.8) + multi_xml (>= 0.5.2) i18n (0.6.11) jbuilder (2.2.2) activesupport (>= 3.0.0, < 5) @@ -50,9 +54,17 @@ GEM json (1.8.1) mail (2.6.1) mime-types (>= 1.16, < 3) + method_source (0.8.2) mime-types (2.4.1) minitest (5.4.2) multi_json (1.10.1) + multi_xml (0.5.5) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-rails (0.3.4) + pry (>= 0.9.10) rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) @@ -99,6 +111,7 @@ GEM sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) + slop (3.6.0) spring (1.1.3) sprockets (2.11.0) hike (~> 1.2) @@ -126,8 +139,11 @@ PLATFORMS DEPENDENCIES coffee-rails (~> 4.0.0) + httparty (~> 0.13.5) jbuilder (~> 2.0) jquery-rails + pry + pry-rails rails (= 4.1.6) rspec-rails sass-rails (~> 4.0.3) diff --git a/source/app/assets/stylesheets/scaffolds.css.scss b/source/app/assets/stylesheets/scaffolds.css.scss new file mode 100644 index 0000000..6ec6a8f --- /dev/null +++ b/source/app/assets/stylesheets/scaffolds.css.scss @@ -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; + } +} diff --git a/source/app/controllers/urls_controller.rb b/source/app/controllers/urls_controller.rb index ef26710..897e7e5 100644 --- a/source/app/controllers/urls_controller.rb +++ b/source/app/controllers/urls_controller.rb @@ -1,2 +1,62 @@ class UrlsController < ApplicationController + before_action :set_url, only: [:edit, :update, :destroy] + before_action :set_url_by_shortened, only: [:show] + + def index + @urls = Url.all + end + + def show + @url.increment(:click_count); @url.save + redirect_to @url.original + end + + def new + @url = Url.new + end + + def edit + end + + def create + @url = Url.new(url_params) + + respond_to do |format| + if @url.save + format.html { redirect_to urls_path, notice: 'Url was successfully created.' } + else + format.html { render :new } + end + end + end + + def update + respond_to do |format| + if @url.update(url_params) + format.html { redirect_to urls_path, notice: 'Url was successfully updated.' } + else + format.html { render :edit } + end + end + end + + def destroy + @url.destroy + respond_to do |format| + format.html { redirect_to urls_path, notice: 'Url was successfully destroyed.' } + end + end + + private + def set_url + @url = Url.find(params[:id]) + end + + def set_url_by_shortened + @url = Url.find_by(shortened: params[:shortened]) + end + + def url_params + params.require(:url).permit(:shortened, :original) + end end diff --git a/source/app/models/url.rb b/source/app/models/url.rb new file mode 100644 index 0000000..251c38a --- /dev/null +++ b/source/app/models/url.rb @@ -0,0 +1,22 @@ +class Url < ActiveRecord::Base + before_save :shorten + + validates :shortened, uniqueness: true + validate :protocol_check, :resolvable_check + + def shorten + self.shortened ||= SecureRandom.urlsafe_base64(5) + end + + def protocol_check + errors[:original] << "URL must begin with http:// or https://" unless original.match(/^https?:\/\//) + end + + def resolvable_check + begin + HTTParty.get(original).code == 200 + rescue + errors[:original] << "not resolvable" + end + end +end diff --git a/source/app/views/urls/_form.html.erb b/source/app/views/urls/_form.html.erb new file mode 100644 index 0000000..041a1ef --- /dev/null +++ b/source/app/views/urls/_form.html.erb @@ -0,0 +1,21 @@ +<%= form_for(@url) do |f| %> + <% if @url.errors.any? %> +
+

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

+ + +
+ <% end %> + +
+ <%= f.label :original %>
+ <%= f.text_field :original %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/source/app/views/urls/edit.html.erb b/source/app/views/urls/edit.html.erb new file mode 100644 index 0000000..e52fdf4 --- /dev/null +++ b/source/app/views/urls/edit.html.erb @@ -0,0 +1,6 @@ +

Editing url

+ +<%= render 'form' %> + +<%= link_to 'Show', @url %> | +<%= link_to 'Back', urls_path %> diff --git a/source/app/views/urls/index.html.erb b/source/app/views/urls/index.html.erb new file mode 100644 index 0000000..8c600db --- /dev/null +++ b/source/app/views/urls/index.html.erb @@ -0,0 +1,28 @@ +

Listing urls

+ + + + + + + + + + + + + <% @urls.each do |url| %> + + + + + + + + <% end %> + +
ClicksShortenedOriginal
<%= url.click_count %><%= link_to url.shortened, shortened_path(url.shortened) %><%= url.original %><%= link_to 'Edit', edit_url_path(url) %><%= link_to 'Destroy', url, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Url', new_url_path %> diff --git a/source/app/views/urls/new.html.erb b/source/app/views/urls/new.html.erb new file mode 100644 index 0000000..7e711d5 --- /dev/null +++ b/source/app/views/urls/new.html.erb @@ -0,0 +1,5 @@ +

New url

+ +<%= render 'form' %> + +<%= link_to 'Back', urls_path %> diff --git a/source/config/routes.rb b/source/config/routes.rb index 3f66539..7bbab78 100644 --- a/source/config/routes.rb +++ b/source/config/routes.rb @@ -1,4 +1,7 @@ Rails.application.routes.draw do + + resources :urls, except: [:show] + get ':shortened' => 'urls#show', as: :shortened # 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/20150601051242_create_urls.rb b/source/db/migrate/20150601051242_create_urls.rb new file mode 100644 index 0000000..e16904d --- /dev/null +++ b/source/db/migrate/20150601051242_create_urls.rb @@ -0,0 +1,10 @@ +class CreateUrls < ActiveRecord::Migration + def change + create_table :urls do |t| + t.string :shortened + t.string :original + + t.timestamps + end + end +end diff --git a/source/db/migrate/20150601143819_add_urls_count.rb b/source/db/migrate/20150601143819_add_urls_count.rb new file mode 100644 index 0000000..605d084 --- /dev/null +++ b/source/db/migrate/20150601143819_add_urls_count.rb @@ -0,0 +1,5 @@ +class AddUrlsCount < 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..b756f97 --- /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: 20150601143819) do + + create_table "urls", force: true do |t| + t.string "shortened" + t.string "original" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "click_count", default: 0 + end + +end