Code Monkey home page Code Monkey logo

playlister-sinatra's Introduction

Sinatra Playlister

Objectives

  • Solidify your ActiveRecord understanding
  • Build out basic views for all your models
  • Create forms for editing and creating a new song that returns a well-structured params hash

Overview

In the theme of moving from a simple command line application static website to dynamic web app, it's time to move Playlister to the interwebs using Sinatra. In this lab, you'll be:

  1. Giving our "library" of songs a dynamic web interface

  2. Creating a few complex forms that allow you to create and edit Artists, Songs and Genres.

File Structure

Your application should use the following file structure. Notice how there are separate controllers for songs, artists, and genres. Separately, we have sub-directories for views for songs, artists, and genres.

├── app
│   ├── controllers
│   │   ├── application_controller.rb
│   │   ├── artists_controller.rb
│   │   ├── genres_controller.rb
│   │   └── songs_controller.rb
│   ├── models
│   │   ├── artist.rb
│   │   ├── concerns
│   │   │   └── slugifiable.rb
│   │   ├── genre.rb
│   │   ├── song.rb
│   │   └── song_genre.rb
│   └── views
│       ├── artists
│       │   ├── index.erb
│       │   └── show.erb
│       ├── genres
│       │   ├── index.erb
│       │   └── show.erb
│       ├── index.erb
│       ├── layout.erb
│       └── songs
│           ├── edit.erb
│           ├── index.erb
│           ├── new.erb
│           └── show.erb

Instructions

The first thing you should aim to do is create a Sinatra interface for the data in db/data. There is a LibraryParser class included in the lib folder that you may use, though it may need some tweaking to work with your specific application. Your associations should follow this pattern:

  1. An Artist can have multiple songs and multiple genres

  2. A Genre can have multiple artists and multiple songs

  3. A Song can belong to ONE Artist and multiple genres

  4. How would we implement the relationship of a song having many genres and genre having many songs? In order to establish a "many-to-many" relationship, we'll need a join table. You will need a SongGenre class to go along with this table in the database

You should build the following routes:

1. /songs

  • This should present the user with a list of all songs in the library.
  • Each song should be a clickable link to that particular song's show page.

2. /genres

  • This should present the user with a list of all genres in the library.
  • Each genre should be a clickable link to that particular genre's show page.

3. /artists

  • This should present the user with a list of all artists in the library.
  • Each artist should be a clickable link to that particular artist's show page.

4. /songs/:slug

  • Any given song's show page should have links to that song's artist and each genre associated with the song.
  • Pay attention to the order of /songs/new and /songs/:slug. The route /songs/new could interpret new as a slug if that controller action isn't defined first.

5. /artists/:slug

  • Any given artist's show page should have links to each of his or her songs and genres.

6. /genres/:slug

  • Any given genre's show page should have links to each of its artists and songs.

To get the data into your database, you will want to figure out how to use your LibraryParser class in the db/seeds.rb file.

How to Approach This Lab

Get the basics of the app working first, which means we have five specs in total and you should first pass all three model specs.

By typing

rspec spec/models/01_artist_spec.rb

in your bash/ command line you will only run that spec. It is important to run the specs in their numeric order. You will notice even after adding a table, model, and controller your specs are still not passing, but the error messages are changing. You have to read every error message carefully to understand what to do next.

For the last spec 05_song_form_spec.rb you need to implement the following features:

1. /songs/new

  • Be able to create a new song
  • Genres should be presented as checkboxes
  • Be able to enter the Artist's name in a text field (only one Artist per song.)

2. /songs/:slug/edit

  • Be able to change everything about a song, including the genres associated with it and its artist.

Think about the custom writer or writers you may need to write to make these features work.

Fixing Migration Errors

While creating your databases, if you make a mistake or want to edit your migrations, you can use rake db:drop to drop any tables that have been created.

If you're having issues while trying to re-migrate, you can also delete schema.rb and any files with the extension .sqlite inside the db folder. Running rake db:migrate will recreate these files.

Slugs

Having a URL like /songs/1 sort of sucks. Imagine trying to email that song to a friend. They would literally have no idea what the song would be until they click the link. You could be sending them literally anything. It would be much better to have a URL like /songs/hot line bling.

But again, we run into a problem here. We can't have spaces in a URL. In order to make it a proper URL, we have to convert the spaces to - in the song name. This is called a slug.

You are going to need to create some slugs in this lab. A slug is used to replace a name that is not acceptable as a URL for various reasons (special characters, spaces, etc). This is great because instead of having a route like /songs/1, you can have a route /songs/hotline-bling which is a much more descriptive route name.

Each class you build will need to have a method to slugify each object's name. This means you'll need to strip out any special characters, and replace all spaces with -.

You'll need to build a method slug which takes a given song/artist/genre name and create the "slugified" version.

The find_by_slug method should use the slug method to retrieve a song/artist/genre from the database and return that entry.

Check Boxes

In order to create a check box of all the genres on a new song form, you'll need to iterate over all the Genres in the database. From there, you'll want to set the genre name as the ID of the input tag.

The value attribute should be set to the genre id.

The name attribute should be set to genres[] because we're dealing with a collection of attributes. This will make the params hash look like this:

params = {
  genres => [ genre1, genre2, genre2]
}
<% Genre.all.each do |genre| %>
<input
  id="<%= genre.name %>"
  type="checkbox"
  name="genres[]"
  value="<%= genre.id %>"
/>
<% end %>

Flash Message

You can add a flash message for when a new instance is created. Let's take a new song creation as an example.

First, add gem 'rack-flash3' to the Gemfile; run bundle to install it.

You can see in Rack Flash's Sinatra section the basics for getting flash messages working with Sinatra.

(Note: You'll need to enable :sessions for your application and use Rack::Flash in the appropriate controller.)

Require rack-flash to the top of the appropriate controller. If this is missed you will receive a NameError: uninitialized constant Rack::Flash message.

You'll want to add a flash message to the post '/songs' and patch '/songs/:slug' actions. post '/songs' might look something like:

post '/songs' do
  # ...
  # ^ code for creating and saving a new song
  flash[:message] = "Successfully created song."
  redirect to("/songs/#{@song.slug}")
end

To display this message in the view, just add

<!-- views/songs/show.erb -->

<% if flash.has?(:message) %> <%= flash[:message] %> <% end %>

to the top of the view.

A Note on the Database

Remember too that you can drop and recreate your database as much as you need to. If you hit a jam, just reset the db, run migrations, and pick up where you left off.

Resources

playlister-sinatra's People

Contributors

ahimmelstoss avatar annjohn avatar arelenglish avatar aviflombaum avatar benjagross avatar curiositypaths avatar danielseehausen avatar dependabot[bot] avatar dwyn avatar fislabstest avatar franknowinski avatar fs-lms-test-bot avatar ihollander avatar ipc103 avatar irmiller22 avatar joshuabamboo avatar kthffmn avatar lizbur10 avatar loganhasson avatar maxwellbenton avatar pletcher avatar preetness avatar realandrewcohn avatar rishter avatar rrcobb avatar sarogers avatar sophiedebenedetto avatar victhevenot avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

playlister-sinatra's Issues

rack-flash may have changed

Hi, I think rack flash may have changed - I wasn't able to get a rack-flash message to persist through a redirect - I was only able to get it to show if I rendered an erb file in the same block that the flash message was created.

instructions not detailed enough

It's my guess that this lab is meant to be challenging and more free-form. Even so, many students in the current class who are going through Sinatra content at home over the break have been stuck on this one. Looking over the instructions and the specs, I think we could give more instruction.

Needs:

  • A bit more to go on for the #slug and .find_by_slug methods. For example, "the #slug method should take a given song/artist/genre name and create the "slugified" version". The .find_by_slug method should use the #slug method"...Right now we don't even explicitly tell them to make these methods, you're just meant to figure it out from the specs.
  • Forms with multiple checkboxes, one for each genre, is really tough. Can we give an example or some more instruction. Also talk about this "checked" option? I'm not 100% positive but I don't think we really do a lot with checkboxes before this lab.
  • Concept of creating a flash message after updating a song isn't discussed anywhere, to my knowledge. There are a number of ways to achieve showing a "successfully updated" message after a song is updated but none of them are discussed or alluded to in this Readme.
  • The associations are confusing because the instructions give them hardly anything to go on. Can we flesh out "you are going to need a join table in there" to something a little more specific? For example, pose it as a question, like: "How would we implement the relationship of a song having many genres and genre having many songs? In order to establish a "many-to-many" relationship, we'll need a join table." I would recommend even explicitly stating you need a SongGenres class and table as the naming of this table tripped up a lot of students.
  • We need to tell them how to set up file structure. You can pass tests w/o having different controllers, subdirectories in views.

Lab directions conflict tests

In the instructions, it tells us to do the following "You will need a SongsGenre class to go along with this table in the database"

However, in the tests, it's looking for this
it "can have many genres" do expect(SongGenre.count).to eq(1) end

Following that direction causes that test to fail. This needs to be either changed in the test or in the instructions to have a consistent class name.

Problematic "database_cleaner" gem in the Gemfile

Hi. First of all, this problem doesn't occur in the in-browser IDE. It only occurs in a local environment (VSCode, in my case).

TL;DR: In the Gemfile, gem 'database_cleaner', git: 'https://github.com/bmabey/database_cleaner.git' should be gem 'database_cleaner'.

Currently, there's a gem in the Gemfile that looks like this: gem 'database_cleaner', git: 'https://github.com/bmabey/database_cleaner.git'

However, when I ran one of the tests (again, from a local environment, not the in-browser IDE), I got this output:

// ♥  learn spec/models/01_artist_spec.rb
D, [2019-08-14T17:53:12.651771 #188] DEBUG -- :    (0.7ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
        Requiring the `database_cleaner` gem directly is deprecated, and will raise an error in database_cleaner 2.0. Instead, please require the specific gem (or gems) for your ORM.
        For example, replace `gem "database_cleaner"` with `gem "database_cleaner-active_record"` in your Gemfile.

An error occurred while loading ./spec/models/01_artist_spec.rb.
Failure/Error: DatabaseCleaner.strategy = :truncation

NameError:
  uninitialized constant DatabaseCleaner::ActiveRecord
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:137:in `orm_module'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:176:in `rescue in require_orm_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:172:in `require_orm_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:168:in `rescue in orm_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:161:in `orm_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:42:in `create_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:66:in `strategy='
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:189:in `set_default_orm_strategy'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:19:in `initialize'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/configuration.rb:81:in `new'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/configuration.rb:81:in `connections'
# /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/configuration.rb:31:in `strategy='
# ./spec/spec_helper.rb:23:in `block in <top (required)>'
# ./spec/spec_helper.rb:18:in `<top (required)>'
# ./spec/models/01_artist_spec.rb:1:in `require'
# ./spec/models/01_artist_spec.rb:1:in `<top (required)>'
# ------------------
# --- Caused by: ---
# NameError:
#   uninitialized constant DatabaseCleaner::ActiveRecord
#   /usr/local/rvm/gems/ruby-2.6.1/bundler/gems/database_cleaner-dd3d7d8c9a8e/lib/database_cleaner/base.rb:137:in `orm_module'
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
No examples found.

Finished in 0.0005 seconds (files took 5.12 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples

The error occurred at this line of code in the spec_helper.rb file: DatabaseCleaner.strategy = :truncation

After some trial and error, I discovered that the previous lab (Sinatra Complex Forms Associations) also had a "database_cleaner" gem. However, that lab worked just fine in my local environment. That's because its Gemfile had this line of code: gem 'database_cleaner'.

I went back to the Sinatra Playlister lab and replaced gem 'database_cleaner', git: 'https://github.com/bmabey/database_cleaner.git' with gem 'database_cleaner'. The tests then worked just fine in my local environment.

I think that's all that needs to be done to fix the issue; there must be something wrong with the repo at https://github.com/bmabey/database_cleaner.git, or else with the way that it's referenced in the Gemfile.

I would really appreciate it if someone looked further into this; it caused me quite the headache for a while.

--- Sdcrouse

One of the song_form_spec tests passes when it shouldn't.

Hi. I found a strange bug in one of the tests that I can't explain. In spec/features/05_song_form_spec.rb there is a test that checks that the songs/new.erb form doesn't make a new Artist if that Artist exists. Somehow, that test passes even when I don't have that functionality in my form.

I poked around with binding.pry and discovered something: Artist.all had the Artist in its array when I paused between lines of code in the test. However, when I paused inside of my get 'songs/new' route, Artist.all returned a blank array; the same was true from within my songs/new.erb file.

Here is what my get 'songs/new' route looks like:

get '/songs/new' do
    @artists = Artist.all
    @genres = Genre.all
    erb :"songs/new"
  end

I don't see anything wrong with my controller. Any Artist that I create, shows up in my index and show pages, so I don't think there's anything wrong with my songs/new.erb file or any of my other routes, either.

Honestly, I have no idea why Artist.all returns a blank array when the test goes into my songs_controller.rb file. I just wanted to bring it to your attention.

Thanks for looking into this, as always.

---Sdcrouse

Rack::Flash causing errors - change to Sinatra::Flash

Rack::Flash was causing the following error on this lab:

/home/marielfrank/playlister-sinatra-v-000/app/controllers/application_controller.rb:7:in '<class:ApplicationController>': uninitialized constant Rack::Flash (NameError)

Switching to Sinatra::Flash, the issues were quickly resolved.

For the ERB,, it would be necessary to change this code:
<% if flash.has?(:message) %> <%= flash[:message] %> <% end %>

to:

<% if !!flash[:message] %> <%= flash[:message] %> <% end %>

Test all the redirects

Pretty much whenever a user hit submit, we need to check that they are then redirected to the right place and the action of the form is a sensible URL

song_form_spec tests for the wrong genre name

In line 37 of spec/05_song_form_spec.rb, the Capybara tests check the checkbox labelled "Hippity Hop", which is the value assigned to the rspec variable song_2_name. Then, in line 43, the test checks for the presence of the variable song_1_name, as in the previous test. This line should read:

expect(page).to have_content(genre_2_name)

seed file usage unclear

this is first time students being required to interact with seed file. So we need to answer questions:

  • what is the purpose of a seed file?
  • what code belongs in there?

Depracation of RSpec configuration

ruby 2.3.0

Debug

Deprecation Warnings:

RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values= is deprecated, it is now set to true as default and setting it to false has no effect.


If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

Solution

# ./spec/spec_helper.rb:15
RSpec.configure do |config|
  # config.treat_symbols_as_metadata_keys_with_true_values = true
  config.run_all_when_everything_filtered = true
  config.filter_run :focus
  config.include Rack::Test::Methods
  config.include Capybara::DSL
  DatabaseCleaner.strategy = :truncation

submitted pull request. do I just clone it and make changes to spec then push it back after pull request is approved?

Error in 04_basic_view_spec.rb

in lines 53-56 of 04_basic_view_spec.rb , the test says:

53 it "contains links to each song's show page" do
54 expect(page).to have_css("a[href='/artists/#{@artist.slug}']")
55 end
56 end

It should say:
53 it "contains links to each ARTIST'S show page" do

Lets that aren't being used anyhwere

here

let!(:blank_pop) { SongGenre.create(:song_id => blank_space.id, :genre_id => pop.id) }
let!(:blank_funk) { SongGenre.create(:song_id => blank_space.id, :genre_id => funk.id) }

I get that they are being used to set up the relationship, but if that's all they are being used for then just put it in a before block and assign them the normal way. Don't modify the JOIN table.

Sinatra bug => update gemfile.lock

I was getting the following error:

Failures:

  1) Song Forms /songs/new without an existing artist creates a new song and a new artist and associates them
     Failure/Error: visit "/songs/new"
     NoMethodError:
       undefined method `join' for #<String:0x007fea2525f0c8> 

from './spec/features/05_song_form_spec.rb:17'. After some research I found that this was a known bug in Sinatra 1.4.5. Even though I had the new gem, it wasn't being used here. Updating the Gemfile.lock to:

sinatra (1.4.6)

will fix that issue for future students.

I have errors

Hi

I have errors and 2 instructors looked at it
and nobody knows why it says errors. ... i already spent 3 days and dont know what to do

Checkboxes don't have names so the check methods in capybara don't work

This code (

uncheck "New Age Garbage"
check "Hippity Hop"
) is looking for a checkbox with the is "hippity hoppity". Problem is, checkboxes are weird so students are having to make the name paramet hippitoy hoppity for this which is bad.

Instead, these tests should do something like checkbox.first to grab the first checkbox and then either check it or not check it. Which requires that the first checkbox is hippity hoppity. We are giving them the data so hopefully that doesn't matter. Worst comes to worst, we can do an id check

I want to use Windows without install ubuntu

How can I make ruby gem using windows without installing Ubuntu.
I made my first project on visual studio on windows without installing Ubuntu.
I tried to install lessons and try to run tests but it didn't work.

I want to know how to create ruby gem using windows without installing Ubuntu and run tests.

Mis-leading specifications

There is no redirect happening here. If you follow the spec description not the implementation it suggests to use a redirect not a render. In Sinatra there is a difference between redirect and render. Please be more explicit.

    context "changing a song's artist" do

      it "updates the song's artist" do
        fill_in "Artist Name", with: "Some Nobody"
        click_on "Save"

        expect(page).to have_content("Song successfully updated.")
        expect(page).to have_content(song_name)
        expect(page).to have_content("Some Nobody")
      end

      it "redirects to the song show page" do
        fill_in "Artist Name", with: "That singer"
        click_on "Save"
        expect(page.current_path).to eq("/songs/that-one-with-the-guitar")
      end
    end

rack-flash instructions could be fleshed out

Either the gem has changed, or the instructions linked in this section of the lab are not correct, because by following those instructions, I was not able to get around the "Uninitialized Constant Rack::Flash" error that students have reported previously, and ended up having to hard-code the message into the show route to pass the tests.

'require_all' doesn't seem to work

Though I'm not sure why, I believe that the 'require_all' implementation in this lab is not functioning properly. Modules in the lib/ folder are not found in the models.

Like the library_parser in there also does, modules raise uninitializes constant errors in the namespaces of the classes where they are included. However, manually requiring the files at the top of the model file does the trick, so it seems to be 'require_all' that is the culprit.

Genre removal

Would suggest adding a test that checks that the application properly handles the removal of a song's genre during song editing.

another typo in 04_basic_view_spec.rb

lines 72-76 say:
72 it "contains links to each song's show page" do
73 expect(page).to have_css("a[href='/genres/#{@genre.slug}']")
74 end
75 end
76 end

should say:
72 it "contains links to each GENRE'S show page" do

unsure of issues

had several issues, even after using solution? could not get all tests to pass properly?

Handraise Issue - TSiege

Test creates duplicate rows. Needs to destroy duplicates from DB in the last describe block in song_form_spec.rb
Also needs to then create a second genre.

Order of routes in Song

Maybe worth putting something in the README about order of routes, I spent a few hours on an issue only to find that get'songs/new' would need to be above get'songs/slug' as the the word new in the first route could be construed as a slug.

create action NoMethodError: undefined method `join' for #<string

Not sure what I am doing to cause this that hasn't happened with other people. Happened in my tests and also when running the app locally.

It was fixed by adding this to my gemfile:
gem 'sinatra-fix_951', require: 'sinatra/fix_951'

Was able to re-create the issue by commenting the above line in my gemfile.

It is fixed in newer versions of sinatra as well.
The issues thread on the problem in sinatra is here sinatra/sinatra#951 .

Rolling back migrations doesnt clear schema for test database

If you make an error building out your database tables and rollback your migrations and/or delete the schema, the test environment persists the database and prevents new migrations or changes from being migrated. There is no clear way to , the only way I could find around this after connecting with T.A.s and instructors and trying all form of rake commands (ie reset, clear, dump) to find a solution was to delete the entire lab, reclone, and start from scratch.

minor tone issue

I thought we were going to avoid using "I" statements? And stick with "we" and "you". On a tough lab like this, students tend to get frustrated. Little things like tone can help mitigate that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.