diff --git a/source/Gemfile b/source/Gemfile index 9627b8b..83bec13 100644 --- a/source/Gemfile +++ b/source/Gemfile @@ -36,6 +36,10 @@ gem 'spring', group: :development # gem 'capistrano-rails', group: :development # Use debugger -# gem 'debugger', group: [:development, :test] - gem 'rspec-rails', group: [:development, :test] - +group :development, :test do + gem 'byebug' + gem 'web-console', '2.0.0.beta3' + gem 'rspec-rails' + gem 'faker', '1.4.2' + gem 'pry' +end diff --git a/source/Gemfile.lock b/source/Gemfile.lock index fcf8b98..4a01e7e 100644 --- a/source/Gemfile.lock +++ b/source/Gemfile.lock @@ -28,7 +28,14 @@ GEM thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) + binding_of_caller (0.7.3.pre1) + debug_inspector (>= 0.0.1) builder (3.2.2) + byebug (3.5.1) + columnize (~> 0.8) + debugger-linecache (~> 1.2) + slop (~> 3.6) + coderay (1.1.0) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -36,9 +43,14 @@ GEM coffee-script-source execjs coffee-script-source (1.8.0) + columnize (0.9.0) + debug_inspector (0.0.2) + debugger-linecache (1.2.0) diff-lcs (1.2.5) erubis (2.7.0) execjs (2.2.1) + faker (1.4.2) + i18n (~> 0.5) hike (1.2.3) i18n (0.6.11) jbuilder (2.2.2) @@ -50,9 +62,14 @@ 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) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) @@ -99,6 +116,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) @@ -120,14 +138,22 @@ GEM uglifier (2.5.3) execjs (>= 0.3.0) json (>= 1.8.0) + web-console (2.0.0.beta3) + activemodel (~> 4.0) + binding_of_caller (= 0.7.3.pre1) + railties (~> 4.0) + sprockets-rails (>= 2.0, < 4.0) PLATFORMS ruby DEPENDENCIES + byebug coffee-rails (~> 4.0.0) + faker (= 1.4.2) jbuilder (~> 2.0) jquery-rails + pry rails (= 4.1.6) rspec-rails sass-rails (~> 4.0.3) @@ -136,3 +162,4 @@ DEPENDENCIES sqlite3 turbolinks uglifier (>= 1.3.0) + web-console (= 2.0.0.beta3) diff --git a/source/app/assets/stylesheets/application.css b/source/app/assets/stylesheets/application.css index a443db3..d1d614e 100644 --- a/source/app/assets/stylesheets/application.css +++ b/source/app/assets/stylesheets/application.css @@ -13,3 +13,12 @@ *= require_tree . *= require_self */ +.debug_dump { + clear: both; + float: left; + width: 100%; + margin-top: 45px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} diff --git a/source/app/controllers/gt_controller.rb b/source/app/controllers/gt_controller.rb new file mode 100644 index 0000000..706ea78 --- /dev/null +++ b/source/app/controllers/gt_controller.rb @@ -0,0 +1,11 @@ + +class GtController < ApplicationController + + def show + @url = Url.find_by short_link: params[:id] + @url.click_count += 1 + @url.save + redirect_to @url.link + end + +end diff --git a/source/app/controllers/urls_controller.rb b/source/app/controllers/urls_controller.rb index ef26710..428939f 100644 --- a/source/app/controllers/urls_controller.rb +++ b/source/app/controllers/urls_controller.rb @@ -1,2 +1,30 @@ class UrlsController < ApplicationController + def index + @urls = Url.all + end + + def show + @url = Url.find(params[:id]) + end + + def create + @url = Url.new(url_params) + if @url.save + flash[:success] = "We created a shorter link! :)" + redirect_to @url + else + flash[:error] = "We could not create your link :(" + render :edit + end + end + + def new + @url = Url.new + end + + private + + def url_params + params.require(:url).permit(:link) + end end diff --git a/source/app/models/url.rb b/source/app/models/url.rb new file mode 100644 index 0000000..02e2dc7 --- /dev/null +++ b/source/app/models/url.rb @@ -0,0 +1,22 @@ +class Url < ActiveRecord::Base + validates :link, presence: true + before_create :create_short_url + validate :url_is_valid, on: :create + + private + def create_short_url + self.short_link = (SecureRandom.random_number(9999999) + 100000).to_s(36) + end + + def url_is_valid + url = URI.parse(link) + req = Net::HTTP.new(url.host, url.port) + req.use_ssl = (url.scheme == 'https') + path = url.path if url.path.present? + res = req.request_head(path || '/') + errors.add(:link, 'must return status code < 400') if res.code.to_i >= 400 + rescue URI::Error + errors.add(:link, 'could not be reached') + end + +end diff --git a/source/app/views/layouts/application.html.erb b/source/app/views/layouts/application.html.erb index f946432..0616281 100644 --- a/source/app/views/layouts/application.html.erb +++ b/source/app/views/layouts/application.html.erb @@ -9,6 +9,6 @@ <%= yield %> - +<%= debug(params) if Rails.env.development? %> diff --git a/source/app/views/shared/_error_messages.html.erb b/source/app/views/shared/_error_messages.html.erb new file mode 100644 index 0000000..6a0f201 --- /dev/null +++ b/source/app/views/shared/_error_messages.html.erb @@ -0,0 +1,5 @@ +<% if @url.errors.any? %> + This link could not be saved: + <%= @url.errors.full_messages %> +<% end %> +<%= console %> diff --git a/source/app/views/urls/_url.html.erb b/source/app/views/urls/_url.html.erb new file mode 100644 index 0000000..7e306f1 --- /dev/null +++ b/source/app/views/urls/_url.html.erb @@ -0,0 +1,3 @@ +
  • + <%= url.link %> - <%= url.short_link %> +
  • diff --git a/source/app/views/urls/edit.html.erb b/source/app/views/urls/edit.html.erb new file mode 100644 index 0000000..ccc547a --- /dev/null +++ b/source/app/views/urls/edit.html.erb @@ -0,0 +1,8 @@ +

    A url!

    + +<%= render 'shared/error_messages' %> +<%= @url.link %> +- +<%= @url.short_link %> + +<%= console %> diff --git a/source/app/views/urls/index.html.erb b/source/app/views/urls/index.html.erb new file mode 100644 index 0000000..2d87f77 --- /dev/null +++ b/source/app/views/urls/index.html.erb @@ -0,0 +1,7 @@ +

    All Urls

    + + + + diff --git a/source/app/views/urls/new.html.erb b/source/app/views/urls/new.html.erb new file mode 100644 index 0000000..6ea3335 --- /dev/null +++ b/source/app/views/urls/new.html.erb @@ -0,0 +1,16 @@ +

    A new url

    + +
    + <%= form_for(@url) do |f| %> + + + <%= f.label :link %> + <%= f.text_field :link %> + + <%= f.label :short_link %> + <%= :short_link %> + + <%= f.submit "Shorten my url" %> + + <% end %> +
    diff --git a/source/app/views/urls/show.html.erb b/source/app/views/urls/show.html.erb new file mode 100644 index 0000000..227c9a8 --- /dev/null +++ b/source/app/views/urls/show.html.erb @@ -0,0 +1,9 @@ +

    A url!

    + +Link: +<%= @url.link %> +
    +Short Link: +<%= @url.short_link %> +
    +Clicks: <%= @url.click_count %> diff --git a/source/config/environments/development.rb b/source/config/environments/development.rb index ddf0e90..afc5268 100644 --- a/source/config/environments/development.rb +++ b/source/config/environments/development.rb @@ -34,4 +34,6 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + config.web_console.automount = true end diff --git a/source/config/routes.rb b/source/config/routes.rb index 3f66539..fb57a8c 100644 --- a/source/config/routes.rb +++ b/source/config/routes.rb @@ -1,4 +1,9 @@ Rails.application.routes.draw do + root 'urls#index' + get 'urls/new' + get 'gt/:id' => 'gt#show' + resources :urls + get ':id' => 'gt#show' # 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/20150115201035_create_urls.rb b/source/db/migrate/20150115201035_create_urls.rb new file mode 100644 index 0000000..494d09f --- /dev/null +++ b/source/db/migrate/20150115201035_create_urls.rb @@ -0,0 +1,9 @@ +class CreateUrls < ActiveRecord::Migration + def change + create_table :urls do |t| + t.string :link + + t.timestamps null:false + end + end +end diff --git a/source/db/migrate/20150116140521_add_short_link_to_urls.rb b/source/db/migrate/20150116140521_add_short_link_to_urls.rb new file mode 100644 index 0000000..e54c049 --- /dev/null +++ b/source/db/migrate/20150116140521_add_short_link_to_urls.rb @@ -0,0 +1,5 @@ +class AddShortLinkToUrls < ActiveRecord::Migration + def change + add_column :urls, :short_link, :string + end +end diff --git a/source/db/migrate/20150116163319_add_click_counter_to_urls.rb b/source/db/migrate/20150116163319_add_click_counter_to_urls.rb new file mode 100644 index 0000000..3341970 --- /dev/null +++ b/source/db/migrate/20150116163319_add_click_counter_to_urls.rb @@ -0,0 +1,5 @@ +class AddClickCounterToUrls < 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..a6e83f9 --- /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: 20150116163319) do + + create_table "urls", force: true do |t| + t.string "link" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "short_link" + t.integer "click_count", default: 0 + end + +end diff --git a/source/db/seeds.rb b/source/db/seeds.rb index 4edb1e8..30e2fdd 100644 --- a/source/db/seeds.rb +++ b/source/db/seeds.rb @@ -5,3 +5,6 @@ # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) +99.times do |n| + Url.create!(link: Faker::Internet.url) +end diff --git a/source/test/controllers/gt_controller_test.rb b/source/test/controllers/gt_controller_test.rb new file mode 100644 index 0000000..48bdb8e --- /dev/null +++ b/source/test/controllers/gt_controller_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class GtControllerTest < ActionController::TestCase + def setup + @url = urls(:google) + end + + test "should redirect to link if given short_link" do + get :show, id: @url.short_link + assert_redirected_to @url.link + end + + test "should increment click counter" do + assert_difference '@url.click_count', 1 do + get :show, id: @url.short_link + @url.reload + end + end +end diff --git a/source/test/controllers/urls_controller_test.rb b/source/test/controllers/urls_controller_test.rb index 469d85c..47b00ff 100644 --- a/source/test/controllers/urls_controller_test.rb +++ b/source/test/controllers/urls_controller_test.rb @@ -1,7 +1,8 @@ require 'test_helper' class UrlsControllerTest < ActionController::TestCase - # test "the truth" do - # assert true - # end + def setup + @url = urls(:google) + end + end diff --git a/source/test/fixtures/urls.yml b/source/test/fixtures/urls.yml new file mode 100644 index 0000000..a6283ad --- /dev/null +++ b/source/test/fixtures/urls.yml @@ -0,0 +1,4 @@ + +google: + link: www.google.com + short_link: shrt12 diff --git a/source/test/models/url_test.rb b/source/test/models/url_test.rb new file mode 100644 index 0000000..9869ee4 --- /dev/null +++ b/source/test/models/url_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' + +class UrlTest < ActiveSupport::TestCase + def setup + @url = Url.new(link: "www.google.com") + end + + test "Url has a link" do + assert_equal @url.link, "www.google.com" + end + + test "Url has a shortened link after saving" do + @url.save! + assert_not_nil @url.short_link, "test123" + end +end