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

Chitter - Eleanor CS #218

Open
wants to merge 9 commits into
base: main
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ruby '3.0.2'

gem 'pg'
gem 'sinatra'
gem 'sinatra-contrib'

group :test do
gem 'capybara'
Expand Down
11 changes: 11 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ GEM
diff-lcs (1.4.4)
docile (1.4.0)
mini_mime (1.1.1)
multi_json (1.15.0)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
nokogiri (1.12.3-arm64-darwin)
racc (~> 1.4)
nokogiri (1.12.3-x86_64-darwin)
racc (~> 1.4)
parallel (1.20.1)
Expand Down Expand Up @@ -75,6 +78,12 @@ GEM
rack (~> 2.2)
rack-protection (= 2.1.0)
tilt (~> 2.0)
sinatra-contrib (2.1.0)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.1.0)
sinatra (= 2.1.0)
tilt (~> 2.0)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
tilt (2.0.10)
Expand All @@ -83,6 +92,7 @@ GEM
nokogiri (~> 1.8)

PLATFORMS
arm64-darwin-21
x86_64-darwin-20

DEPENDENCIES
Expand All @@ -93,6 +103,7 @@ DEPENDENCIES
simplecov
simplecov-console
sinatra
sinatra-contrib

RUBY VERSION
ruby 3.0.2p107
Expand Down
30 changes: 30 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
require 'sinatra/base'
require './lib/peeps'

class Chitter < Sinatra::Base

Choose a reason for hiding this comment

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

You could probably delete this test route.

get '/test' do
'Test page'
end

get '/' do

Choose a reason for hiding this comment

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

these are generally good RESTful routes – nice work!

You could consider ways of combining the routes for all the requests that show multiple Peeps but, then again, you could also make the argument that such an approach would break SRP.

'Welcome to Chitter!'
erb :index
end

get '/peeps' do
@peeps = Peeps.all
erb :peeps
end

get '/peeps/new' do
erb :new_peep
end

post '/peeps' do
Peeps.create(message: params[:message], entry_date: params[:entry_date])
redirect '/peeps'
end

get '/peeps/reverse' do
@peeps = Peeps.reverse_chronology
erb :peeps_reverse
end

get '/peeps/filter' do
@filtered_peeps = Peeps.filter(params[:filter])
erb :peeps_filter
end

run! if app_file == $0
end
Binary file added chitter_image.jpeg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions db/migrations/01_add_date_column.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE peeps ADD entry_date date;
57 changes: 57 additions & 0 deletions lib/peeps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require 'pg'

class Peeps

attr_reader :id, :message, :entry_date, :filter

def initialize(id:, message:, entry_date:)
@id = id
@message = message
@entry_date = entry_date
end

def self.open_connection

Choose a reason for hiding this comment

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

It's possible to refactor this into its own class and have an always on db connection while the app is running. There's a walkthrough on how to do this in Ex.15 on the Bookmark task.

if ENV['ENVIRONMENT'] == 'test'
connection = PG.connect(dbname: 'chitter_test')
else
connection = PG.connect(dbname: 'chitter')
end
end

def self.row_to_peep(row)
Peeps.new(id: row['id'], message: row['message'], entry_date: row['entry_date'])
end

def self.all
connection = open_connection

result = connection.exec("SELECT * FROM peeps;")
result.map do |peep|
row_to_peep(peep)

Choose a reason for hiding this comment

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

This line being refactored into its own method is nice

end
end

def self.create(message:, entry_date:)
connection = open_connection

result = connection.exec_params("INSERT INTO peeps (message, entry_date) VALUES($1, $2) RETURNING id, message, entry_date;", [message, entry_date])
row_to_peep(result[0])
end

def self.reverse_chronology
connection = open_connection

result = connection.exec("SELECT * FROM peeps ORDER BY entry_date DESC;")

Choose a reason for hiding this comment

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

Oh interesting, I did this with a .reverse method on the array.

Choose a reason for hiding this comment

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

Which approach is more computationally efficient? How would you test it?

result.map do |peep|
row_to_peep(peep)
end
end

def self.filter(filter)
connection = open_connection
result = connection.exec("SELECT * FROM peeps WHERE lower(message) LIKE '%#{filter.downcase}%';")

Choose a reason for hiding this comment

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

Using downcase on everything is better than what I did

Choose a reason for hiding this comment

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

It's a nice approach, I agree!

result.map do |peep|
row_to_peep(peep)
end
end
end
7 changes: 7 additions & 0 deletions spec/database_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'pg'

def persisted_data(id:)
connection = PG.connect(dbname: 'chitter_test')
result = connection.query("SELECT * FROM peeps WHERE id = #{id};")
result.first
end
15 changes: 15 additions & 0 deletions spec/features/creating_peeps_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
feature 'Creating peeps' do
scenario 'user can add peeps and dates' do
setup_test_database

Peeps.create(message: 'Test peep!', entry_date: "2021-03-18")
Peeps.create(message: 'Second test peep!', entry_date: "2021-02-15")

visit ('/peeps')

expect(page).to have_content('Test peep!')
expect(page).to have_content('Second test peep!')
expect(page).to have_content("2021-03-18")
expect(page).to have_content("2021-02-15")
end
end
15 changes: 15 additions & 0 deletions spec/features/filter_peeps_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
feature 'Filtering peeps' do
scenario 'user can filter peeps by keyword' do
setup_test_database

Peeps.create(message: 'Test peep!', entry_date: "2021-03-18")
Peeps.create(message: 'Second test peep!', entry_date: "2021-02-15")

visit ('/peeps')
fill_in('filter', with: 'peep')

Choose a reason for hiding this comment

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

Given that both test peeps contain the word 'peep' maybe another word could have been used to test the filter function, such as 'Second'? Even better would be 'second' as then you test your downcase code as well.

Choose a reason for hiding this comment

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

Good points!

click_button "Filter"

expect(page).to have_content("Test peep!")
expect(page).to have_content("Second test peep!")
end
end
14 changes: 14 additions & 0 deletions spec/features/reverse_chronological_order_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
feature 'Reverse chronological peeps' do
scenario 'user can see most recent peeps first' do
setup_test_database

Peeps.create(message: 'Test peep!', entry_date: "2021-03-18")
Peeps.create(message: 'Second test peep!', entry_date: "2021-02-15")

visit ('/peeps')

click_button "View Newest First"

page.body.index("2021-03-18").should < page.body.index("2021-02-15")

Choose a reason for hiding this comment

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

I have never seen page.body.index before. Nice.

Choose a reason for hiding this comment

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

Neither have I :)

end
end
13 changes: 13 additions & 0 deletions spec/features/viewing_peeps_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
feature 'Viewing peeps' do
scenario 'user can view all peeps' do
setup_test_database

Peeps.create(message: 'Test peep!', entry_date: "2021-03-18")
Peeps.create(message: 'Second test peep!', entry_date: "2021-02-15")

visit ('/peeps')

expect(page).to have_content('Test peep!')
expect(page).to have_content('Second test peep!')
end
end
44 changes: 44 additions & 0 deletions spec/peeps_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'peeps'

describe '.all' do
it 'returns a list of peeps' do
setup_test_database

chitter = Peeps.create(message: "Test peep!", entry_date: "2021-02-15")
Peeps.create(message: "Second test peep!", entry_date: "2021-02-13")
Peeps.create(message: "Third test peep!", entry_date: "2021-10-16")

chitter = Peeps.all

expect(chitter.length).to eq 3
expect(chitter.first).to be_a Peeps
expect(chitter.first.message).to eq "Test peep!"
expect(chitter.first.entry_date).to eq "2021-02-15"
end
end

require 'database_helpers'

describe '.create' do
it 'creates a new peep' do
chitter = Peeps.create(message: "Test peep!", entry_date: "2021-02-15")
persisted_data = persisted_data(id: chitter.id)

expect(chitter).to be_a Peeps
expect(chitter.id).to eq persisted_data['id']
expect(chitter.message).to eq "Test peep!"
expect(chitter.entry_date).to eq "2021-02-15"
end
end

describe '.filter' do
it 'filters peeps by keyword' do
chitter = Peeps.create(message: "Test peep!", entry_date: "2021-02-15")
Peeps.create(message: "Second test peep!", entry_date: "2021-02-13")
Peeps.create(message: "Third say hello!", entry_date: "2021-10-16")

filtered_results = Peeps.filter("Peep")
expect(filtered_results[0].message).to eq "Test peep!"
expect(filtered_results[1].message).to eq "Second test peep!"
end
end
2 changes: 2 additions & 0 deletions views/index.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1> Welcome to Chitter! </h1>
<img src="https://gl.audubon.org/sites/default/files/styles/hero_mobile/public/aud_apa-2020_barn-swallow_a1-11258-1_nape_photo-xianwei-zeng.jpg?itok=aTU-t6nJ" alt="Chitter Birds">

Choose a reason for hiding this comment

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

Maybe this picture could link to your /peeps page?

5 changes: 5 additions & 0 deletions views/new_peep.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<form action="/peeps" method="post">
<input type="text" name="message" placeholder="Message" />
<input type="date" name="entry_date" />
<input type="submit" value="Submit" />
</form>
19 changes: 19 additions & 0 deletions views/peeps.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<h1> Welcome to Chitter! </h1>


<% @peeps.each do |peep| %>
<div class="Peeps" style="border: 3px solid aqua; width:fit-content; width:-webkit-fit-content; width:-moz-fit-content;">

Choose a reason for hiding this comment

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

The styling would be better placed in a css file I reckon, especially given that this code will repeat on every iteration of the loop.

<q><%= peep.message %></q>
<i><%= peep.entry_date %></i>
</div>
<% end %>

<form action="/peeps/reverse" method="get">

Choose a reason for hiding this comment

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

Love that this is a button (I did mine the lazy way!)

<input type="submit" value="View Newest First" />
</form>

<form action="/peeps/filter" method="get">
<input type="text" name="filter" placeholder="Filter keyword" />
<input type="submit" value="Filter" />
</form>

10 changes: 10 additions & 0 deletions views/peeps_filter.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h1> Welcome to Chitter! </h1>

<h2> Here are your filtered results: </h2>

<% @filtered_peeps.each do |peep| %>
<div class="Peeps" style="border: 3px solid aqua; width:fit-content; width:-webkit-fit-content; width:-moz-fit-content;">
<q><%= peep.message %></q>
<i><%= peep.entry_date %></i>
</div>
<% end %>
8 changes: 8 additions & 0 deletions views/peeps_reverse.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h1> Welcome to Chitter! </h1>

<% @peeps.each do |peep| %>
<div class="Peeps" style="border: 3px solid aqua; width:fit-content; width:-webkit-fit-content; width:-moz-fit-content;">
<q><%= peep.message %></q>
<i><%= peep.entry_date %></i>
</div>
<% end %>