Skip to content
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

complete solution(Shabbir Saifee) #37

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion source/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@ gem 'spring', group: :development
# Use debugger
# gem 'debugger', group: [:development, :test]
gem 'rspec-rails', group: [:development, :test]

103 changes: 54 additions & 49 deletions source/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,35 @@ GEM
thread_safe (~> 0.1)
tzinfo (~> 1.1)
arel (5.0.1.20140414130214)
builder (3.2.2)
builder (3.2.3)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.3.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.8.0)
diff-lcs (1.2.5)
coffee-script-source (1.12.2)
concurrent-ruby (1.0.5)
diff-lcs (1.3)
erubis (2.7.0)
execjs (2.2.1)
execjs (2.7.0)
hike (1.2.3)
i18n (0.6.11)
jbuilder (2.2.2)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
jquery-rails (3.1.2)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jbuilder (2.6.4)
activesupport (>= 3.0.0)
multi_json (>= 1.2)
jquery-rails (3.1.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
mail (2.6.1)
mime-types (>= 1.16, < 3)
mime-types (2.4.1)
minitest (5.4.2)
multi_json (1.10.1)
rack (1.5.2)
rack-test (0.6.2)
json (1.8.6)
mail (2.7.0)
mini_mime (>= 0.1.1)
mini_mime (1.0.0)
minitest (5.11.3)
multi_json (1.13.1)
rack (1.5.5)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.1.6)
actionmailer (= 4.1.6)
Expand All @@ -71,55 +73,55 @@ GEM
activesupport (= 4.1.6)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.3.2)
rdoc (4.1.2)
json (~> 1.4)
rspec-core (3.1.6)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
rake (12.3.0)
rdoc (4.3.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.1.0)
rspec-mocks (3.1.3)
rspec-support (~> 3.1.0)
rspec-rails (3.1.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-rails (3.7.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-support (~> 3.1.0)
rspec-support (3.1.2)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.1)
sass (3.2.19)
sass-rails (4.0.3)
sass-rails (4.0.5)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sass (~> 3.2.2)
sprockets (~> 2.8, < 3.0)
sprockets-rails (~> 2.0)
sdoc (0.4.1)
sdoc (0.4.2)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
spring (1.1.3)
sprockets (2.11.0)
spring (1.7.2)
sprockets (2.12.4)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.2.0)
sprockets-rails (2.3.3)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
sqlite3 (1.3.9)
thor (0.19.1)
thread_safe (0.3.4)
sqlite3 (1.3.13)
thor (0.20.0)
thread_safe (0.3.6)
tilt (1.4.1)
turbolinks (2.4.0)
coffee-rails
tzinfo (1.2.2)
turbolinks (5.1.0)
turbolinks-source (~> 5.1)
turbolinks-source (5.1.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (2.5.3)
execjs (>= 0.3.0)
json (>= 1.8.0)
uglifier (4.1.6)
execjs (>= 0.3.0, < 3)

PLATFORMS
ruby
Expand All @@ -136,3 +138,6 @@ DEPENDENCIES
sqlite3
turbolinks
uglifier (>= 1.3.0)

BUNDLED WITH
1.16.1
55 changes: 55 additions & 0 deletions source/app/controllers/urls_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,57 @@
class UrlsController < ApplicationController

#GET /urls
def index
@urls = Url.all
end

#GET /urls/new
def new
@url = Url.new
end
#GET /urls/:id
def show
@url = Url.find(params[:id])
end

# POST /urls
def create
puts "inside create"
@url = Url.new(url_params)
if @url.save
redirect_to url_path(@url)
else
render 'new'
end
end

#DELETE /urls/:id
def destroy
@url =Url.find(params[:id])
if @url.destroy
redirect_to urls_path
else

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy doesn't return true or false to tell you whether it succeeded, like some other ActiveRecord methods. So, just redirect unconditionally.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh Thanks. Is it better if implement the error handling here? because, if destroy fails due to some DB issue it will raise an exception right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question. The destroy call can raise an error for many various reasons. I would not handle those errors in app code as long as we don't expect them from regular app usage. Make sure the app is connected with some error aggregation service, then let "exceptional" exceptions go uncaught.

If we start seeing errors we didn't account for, that's when we should do what we can to prevent them and also rescue them to return a more user-friendly response to our user.

end
end

#GET /:short_url
def hit_short_url
puts "inside hit_url"
url = Url.find_by short_url: params[:short_url]
if url
url.update('click_count' => url.click_count + 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concurrent clicks will be undercounted. Not that it really matters for this exercise, but I think it's a fun exercise to think about doing atomic updates to the database records.

redirect_to url.original_url
else
redirect_to root_path
end

end

private
def url_params
params.require(:url).permit(:original_url)
end


end
31 changes: 31 additions & 0 deletions source/app/models/url.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'uri'
class Url < ActiveRecord:: Base

CHARSET = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a)
validates :original_url, presence: true
validate :url_valid?
#before_save :shorten_url, :on => :create
before_create :shorten_url

private def url_valid?
begin
error.add(:original_url, " is invalid!") unless
URI.parse(original_url).kind_of?(URI::HTTP) || URI.parse(original_url).kind_of?(URI::HTTPS)
rescue
errors.add(:original_url, " is invalid! (must start with 'http' or 'https')")
end
end

private def shorten_url
puts "inside shotern method"
self.short_url = create_short_url
end

private def create_short_url
tiny_url =""
6.times do
tiny_url << CHARSET.sample
end
tiny_url
end
end
22 changes: 21 additions & 1 deletion source/app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,30 @@
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" >
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" ></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" ></script>

</head>
<body>
<header class="navbar navbar-inverse">
<div class="navbar-class">
<div class="container">
<ul class="nav navbar-nav">
<li><%= link_to "home", urls_path%></li>
<li><%=link_to "shorten url", new_url_path %></li>
</ul>


</div>
</div>
</header>

<div class="container-fluid">
<%= yield %>
</div>

<%= yield %>

</body>
</html>
23 changes: 23 additions & 0 deletions source/app/views/urls/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<h1>
Listing all the urls
</h1>

<p> <%= link_to "Shorten Url", new_url_path %>
</p>

<table >
<tr>
<td> <strong> Original Url </strong> </td>
<td> <strong> Shortened Url </strong> </td>
<td> <strong>Total Clicks</strong> </td>
</tr>
<% @urls.each do |url| %>
<tr>
<td> <a href="<%=url.original_url %>" ><%=url.original_url %></a></td>
<td> <a href="http://localhost:3000/<%=url.short_url%>"><%=url.short_url%> </a></td>
<td><%= url.click_count %></td>
<td><%= link_to 'Delete', url_path(url), method: :delete,data: {confirm: "Are you sure?"} %></td>
</tr>

<% end %>
</table>
23 changes: 23 additions & 0 deletions source/app/views/urls/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<h1>Shorten a new url on this page</h1>

<!-- -->

<%if @url.errors.any?%>
<h2> Correct the following errors</h2>
<ul>
<% @url.errors.full_messages.each do |msg| %>
<li class="text-danger">
<%= msg %>
</li>
<%end %>
</ul>

<% end %>

<%= form_for @url do |f| %>
<p>
<%= f.label "Enter Url" %></br>
<%= f.text_field :original_url, class: "form-control" %>
<%=f.submit class: "btn btn-success", value: "Shorten" %>
</p>
<% end %>
8 changes: 8 additions & 0 deletions source/app/views/urls/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h1>showing selected url</h1>

<p>
Original URL: <%= @url.original_url%>
</p>
<p>
Shortened Url: <%= @url.short_url%>
</p>
56 changes: 3 additions & 53 deletions source/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,56 +1,6 @@
Rails.application.routes.draw do
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

# You can have the root of your site routed with "root"
# root 'welcome#index'

# Example of regular route:
# get 'products/:id' => 'catalog#view'

# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase

# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products

# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end

# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end

# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end

# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable

# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
resources :urls
root 'urls#index'
get '/:short_url', to: 'urls#hit_short_url'
end
Loading