-
Notifications
You must be signed in to change notification settings - Fork 40
robert lude's solution #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
76d81c3
fa51777
e50d1ee
b86886f
cbb0b71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,3 +14,7 @@ | |
| # Ignore all logfiles and tempfiles. | ||
| /log/*.log | ||
| /tmp | ||
|
|
||
| # Ignore vim tempfiles | ||
| *.swo | ||
| *.swp | ||
| 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; | ||
| } | ||
| } |
| 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; | ||
| } | ||
| } | ||
| } | ||
| } |
| 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] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another way to do this is to set the callback in the |
||
|
|
||
| # 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| module UrlsHelper | ||
|
|
||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
|
|
||
| require 'socket' | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
|
|
||
| require 'net/http' | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| 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 %> |
| 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 %> |
| 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 %> |
| 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 |
| 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 %> |
| 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 %> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| json.extract! @url, :id, :shortcode, :destination, :created_at, :updated_at |
| 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 |
| 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 |
| 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 |
There was a problem hiding this comment.
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/