Skip to content
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
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.4.4
2.4.4
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ gem 'jbuilder', '~> 2.5'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

gem 'jquery-rails'
gem 'devise'
gem 'simple_form'
gem 'will_paginate'
gem 'will_paginate-bootstrap'
gem 'bootstrap-sass', '~> 3.4.1'
gem 'sassc-rails', '>= 2.1.0'
gem 'autoprefixer-rails'
gem 'sprockets-rails'

gem 'annotate'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false

Expand All @@ -45,6 +53,7 @@ group :development, :test do
gem 'rspec-rails', '~> 3.7'
gem 'factory_bot_rails'
gem 'capybara'
gem 'launchy'
gem 'pry'
gem 'rails-controller-testing'
end
Expand Down
37 changes: 36 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,19 @@ GEM
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
annotate (2.7.4)
activerecord (>= 3.2, < 6.0)
rake (>= 10.4, < 13.0)
arel (9.0.0)
autoprefixer-rails (9.4.10.2)
execjs
bcrypt (3.1.12)
bindex (0.5.0)
bootsnap (1.3.0)
msgpack (~> 1.0)
bootstrap-sass (3.4.1)
autoprefixer-rails (>= 5.2.1)
sassc (>= 2.0.0)
builder (3.2.3)
byebug (10.0.2)
capybara (2.18.0)
Expand Down Expand Up @@ -90,6 +98,12 @@ GEM
jbuilder (2.7.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
jquery-rails (4.3.3)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
launchy (2.4.3)
addressable (~> 2.3)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
Expand Down Expand Up @@ -184,6 +198,15 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sassc (2.0.1)
ffi (~> 1.9)
rake
sassc-rails (2.1.0)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
simple_form (4.0.1)
actionpack (>= 5.0)
activemodel (>= 5.0)
Expand Down Expand Up @@ -220,38 +243,50 @@ GEM
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
will_paginate (3.1.6)
will_paginate-bootstrap (1.0.2)
will_paginate (>= 3.0.3)
xpath (3.0.0)
nokogiri (~> 1.8)

PLATFORMS
ruby

DEPENDENCIES
annotate
autoprefixer-rails
bootsnap (>= 1.1.0)
bootstrap-sass (~> 3.4.1)
byebug
capybara
coffee-rails (~> 4.2)
devise
factory_bot_rails
jbuilder (~> 2.5)
jquery-rails
launchy
listen (>= 3.0.5, < 3.2)
pry
puma (~> 3.11)
rails (~> 5.2.0)
rails-controller-testing
rspec-rails (~> 3.7)
sass-rails (~> 5.0)
sassc-rails (>= 2.1.0)
simple_form
spring
spring-watcher-listen (~> 2.0.0)
sprockets-rails
sqlite3
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
will_paginate
will_paginate-bootstrap

RUBY VERSION
ruby 2.4.4p296

BUNDLED WITH
1.16.2
2.0.1
246 changes: 246 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,249 @@ Run the specs with `rspec`
Run the server with `rails s`

View the site at http://localhost:3000

# Backend

## Add pagination to index page, to display 5 dogs per page

app/controllers/dogs_controller.rb

```ruby
@dogs = Dog.paginate(page: params[:page], :per_page => 5)
```

app/views/_dogs.html.erb
```ruby
<%= will_paginate @dogs, renderer: BootstrapPagination::Rails %>
```
## Add the ability to for a user to input multiple dog images on an edit form or new dog form

app/views/_form.html.erb
```ruby
<%= f.input :images, as: :file, :input_html => { :multiple => true } %>
```

app/controllers/dogs_controller.rb
```ruby
def dog_params
params.require(:dog).permit(:name, :description, images: [])
end
```

## Associate dogs with owners

app/models/dog.rb
```ruby
belongs_to :owner, optional: true,
primary_key: :id,
foreign_key: :owner_id,
class_name: 'User'
```

## Allow editing only by owner
app/controllers/dogs_controller.rb
```ruby
before_action :require_login, only: [:new, :create]
```

app/controllers/application_controller.rb
```ruby
def require_login
redirect_to dogs_url unless current_user
end
```
app/views/show.html.erb
```ruby
<% if current_user && current_user.id == @dog.owner_id %>
<%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %>
<%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
```

## Allow users to like other dogs (not their own)

app/controller/likes_controller.rb
```ruby
class LikesController < ApplicationController
before_action :require_login

def create
@like = Like.new(like_params)
@like.liker_id = current_user.id
@like.dog_id = params[:dog_id]

respond_to do |format|
if @like.save
@dog = Dog.find(params[:dog_id])

format.html { redirect_to @dog }
format.json { render :show, status: :created, location: @dog }

else
format.json { render json: @like.errors.full_messages, status: 422 }
end
end

end

def destroy
@like = Like.find(params[:id])
@dog = Dog.find(@like.dog_id)
@like.destroy

respond_to do |format|
format.html { redirect_to @dog }
end
end

private
def like_params
params.permit(:dog_id, :liker_id)
end
end
```

app/views/show.html.erb
```ruby
<% if current_user && @dog.owner_id != current_user.id %>
<% if @like %>
<%= link_to "Unlike", like_url(@like.id), method: :delete %>
<% else %>
<%= link_to "Like", dog_likes_url(@dog), method: :post %>
<% end %>
<% end %>
```

## Allow sorting the index page by number of likes in the last hour
app/controllers/dogs_controller.rb
```ruby
def index
if params[:sort_params]
subquery = Like.select(:id, :dog_id, :user_id).where(created_at: (Time.now - 1.hour)..Time.now)
@dogs = Dog.paginate(page: params[:page], :per_page => 5)
.joins("LEFT JOIN (#{subquery.to_sql}) AS likes ON dogs.id = likes.dog_id")
.group(:id)
.order("count(likes.id) desc")
else
@dogs = Dog.paginate(page: params[:page], :per_page => 5)
end
end
```


## Display the ad.jpg image after every 2 dogs in the index page

app/views/_thumbnail.html.erb
```ruby
<% if dog_counter % 2 == 1 %>
<div class="col-lg-4 col-md-6 col-sm-12 mt-3">
<article>
<h2 class="ad-description">Collar for Sale!</h2>
<%= image_tag image_url('ad.jpg'), class: "ad-photo", alt: "Photo of ad" %>
</article>
</div>
<% end %>
```

# Frontend

## Display profile images in a functioning carousel (for the dog detail page that has more than one profile image)

app/views/show.html.erb
```ruby
<h2 class="text-center"><%= @dog.name %></h2>
<% if @dog.images.length > 1 %>
<section class="pt-3">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<% @dog.images.each_with_index do |image, n| %>
<li data-target="#myCarousel" data-slide-to="<%= n %>" class="<%= n == 0 ? 'active' : '' %>"></li>
<% end %>
</ol>

<!-- Wrapper for slides -->
<div class="carousel-inner">
<% @dog.images.each_with_index do |image, n| %>
<div class="item <%= n == 0 ? 'active' : '' %>">
<%= image_tag url_for(image) %>
</div>
<% end %>
</div>

<!-- Left and right controls -->
<a class="left carousel-control" href="#myCarousel" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">Next</span>
</a>
</div>
</section>
<% else %>
<% @dog.images.each do |image| %>
<%= image_tag url_for(image), class: "item-image mx-auto d-block", alt: "Photo of #{@dog.name}" %>
<% end %>
<% end %>

<section>
<p class="dog-description text-large"><%= @dog.description %></p>
<h2 class="text-center">Likes: <%= @dog.likes.count %></h2>

<div class="text-center text-large">
<% if current_user && @dog.owner_id != current_user.id %>
<% if @like %>
<%= link_to "Unlike", like_url(@like.id), method: :delete %>
<% else %>
<%= link_to "Like", dog_likes_url(@dog), method: :post %>
<% end %>
<% end %>

<% if current_user && current_user.id == @dog.owner_id %>
<%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %>
<%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
</div>
</section>
```

## Use flexbox, CSS grids, or a grid framework to display the homepage's dog profile thumbnails in a responsive grid layout

app/views/_dogs.html.erb
```ruby
<div class="container text-center">
<div class="text-right mb-3 text-dark text-large">
<%= link_to "Sort By Likes", :controller => "dogs", :action => "index", :sort_params => true %>
</div>
<div class="row">
<%= render partial: 'thumbnail', collection: @dogs, as: :dog %>
</div>
<div id="page_links">
<%= will_paginate @dogs, renderer: BootstrapPagination::Rails %>
</div>
</div>
```

## Use utility classes within a layout framework (Bootstrap, Foundation, Material Design, or another) to add a structured layout to the page without custom CSS.

The use of utility classes with Bootstrap can be seen throughout the application.

## Refactor the homepage from its current state as a server-rendered page to a client-rendered page, where you request data from `/dogs.json` and display data from the response.

app/view/index.html.erb
```html
<script>
$(function(){
$('.pagination a').attr('data-remote', 'true')
});
</script>
```
Created a javascript view to to be executed when the ajax request is returned. The following code replaces the contents of the dogs div with the dogs partial. <br />
<br />
app/views/index.js.erb
```javascript
$("#dogs").html('<%= escape_javascript(render 'dogs') %>');
$('.pagination a').attr('data-remote', 'true');
```
2 changes: 2 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require bootstrap-sprockets
//= require_tree .

console.log('Welcome!');
Loading