Giter VIP home page Giter VIP logo

sinatra-mvc-file-structure's Introduction

Sinatra MVC File Structure

Overview

We'll review the file structure we'll be using for our MVC Sinatra applications.

Objectives

  1. Explain the files and folders in a Sinatra MVC file structure
  2. Describe the different folders in the app directory and create new files and add code to these folders
  3. Complete and run a Sinatra MVC application

Keeping Code Organized

We could, if we wanted to, write our entire app in a single file. As you might imagine, this would make things very difficult to read and debug.

Keeping our code organized is crucial when developing complex applications. This concept is called separation of concerns and single responsibility. Each file in our application will have a different responsibility and we'll keep these responsibilities split up into reasonable chunks.

You'll be coding along in this lesson so fork and clone this lab. There are tests to run to make sure your solutions are working. Find the instructions underneath the descriptions for each file you'll be editing.

What does a Sinatra MVC File Structure Look Like?

Take a look at the file structure in this directory. It's okay if it feels overwhelming at first. We're going to walk through the different files and folders and discuss what their responsibilities are.

├── Gemfile
├── README.md
├── app
│   ├── controllers
│   │   └── application_controller.rb
│   ├── models
│   │   └── model.rb
│   └── views
│       └── index.erb
├── config
│   └── environment.rb
├── config.ru
├── public
│   └── stylesheets
└── spec
    ├── controllers
    ├── features
    ├── models
    └── spec_helper.rb

Gemfile

This holds a list of all the gems needed to run the application. The bundler gem provides us access to a terminal command: bundle install. Bundler will look in the Gemfile and install any gems, as well as any gem dependencies for this application.

Go ahead and enter this command in terminal. It will create a Gemfile.lock file for you, which is just a documentation of the specific gem versions that should be installed.

app directory

This folder holds our MVC directories - models, views, and controllers. We spend most of our time coding in this directory.

models directory

This directory holds the logic behind our application. Typically, these files represent either a component of your application, such as a User, Post, or Comment, or a unit of work. Each file in models typically contains a different class. For example, dog.rb would contain a class called Dog. As you might have guessed, models represent the "M" components of the MVC paradigm.

Models represent the data and object logic of our application.

Create a new file in the models directory to create a dog class. This class should have name, breed, and age attributes which can be set on initialization. You should be able to read and write to these attributes. This class should also keep track of each instance of dog created, as well as a class method all to return an array of those instances.

controllers directory

The controllers, such as application_controller.rb, are where the application configurations, routes, and controller actions are implemented. There is typically a class, which in this case we will call ApplicationController, that represents an instance of your application when the server is up and running. The application_controller.rb file represents the "C" components of the MVC paradigm.

(In some simple applications –– including several labs and code-alongs in this track –– the Application Controller will simply be called app.rb and will live in the root directory of the project.)

Sometimes our other controllers will use ApplicationController as an inheritance point so that they inherit all the defaults and behaviors defined in our main ApplicationController. Other times our other controllers will simply inherit from Sinatra::Base.

Controllers represent the application logic, generally; the interface and flow of our application.

Let's go ahead and fill in our controller. You'll notice in application_controller.rb, we have an ApplicationController class that inherits from Sinatra::Base. When we start up a server, the server will spin up an instance of the ApplicationController class to run our app.

You'll also notice there is a configure block already in the controller. This configure block tells the controller where to look to find the views (your pages with HTML to display text in the browser) and the public directory.

When a client makes a request to a server to load an application, the request is received and processed by the controller. We need to set up a controller action to accept the request and respond with the appropriate HTML.

We've created a controller action that can receive and respond to a GET request to the root URL '/'. This GET request loads the index.erb file.

views directory

This directory holds the code that will be displayed in the browser. In a Sinatra app we use .erb files instead of .html files because .erb files allow us to include regular, old HTML tags AND special erb tags which contain Ruby code. We can name them anything we like, but by convention, our file names will match up with the action that renders them. For example, a GET request to / typically renders a file called index.erb.

Views represent how things look and are displayed in our application. We've created a file index.erb that contains some basic HTML code.

We've already told the controller how to load this file in the view.

config.ru file

A config.ru file is necessary when building Rack-based applications and using rackup/shotgun to start the application server (the ru stands for rackup).

config.ru is first responsible for loading our application environment, code, and libraries.

Once all our code is loaded, config.ru then specifies which controllers to load as part of our application using run or use.

In this case, our config.ru file contains the line run ApplicationController, which creates an instance of our ApplicationController class that can respond to requests from a client.

config directory

This directory holds an environment.rb file. We'll be using this file to connect up all the files in our application to the appropriate gems and to each other.

This environment.rb file loads Bundler and thus all the gems in our Gemfile, as well as the app directory.

public directory

The public directory holds our front-end assets. In the example above, it holds a css directory with a stylesheet. Javascript directories and any other front-end assets (like image files) should also be stored in public.

spec directory

The spec directory contains any tests for our applications. These tests set up any expectations for the rest of the project. These are often broken down into unit tests for models, controller tests for routes, and feature tests, which check the actual behavior for users.

Don't forget to run your tests!

sinatra-mvc-file-structure's People

Contributors

annjohn avatar aviflombaum avatar curiositypaths avatar danielseehausen avatar dependabot[bot] avatar dfenjves avatar emilycroft avatar franknowinski avatar gj avatar howardbdev avatar ihollander avatar ipc103 avatar jmburges avatar lizbur10 avatar maxwellbenton avatar mendelb avatar pletcher avatar ruchiramani avatar victhevenot avatar

Stargazers

 avatar  avatar

Watchers

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

sinatra-mvc-file-structure's Issues

Verify accuracy of Gemfile.lock description

The lesson text offers this explanation for the Gemfile.lock file: "The lock word is actually because it makes sure that only one thing is running bundle install at a time." This comes across as incorrect/misleading given that the purpose of the lock file is to document and enforce a specific working gem versions configuration.

Tests issue and file name extension issue

Last test in spec requires 'breed' to be 'dalmation' (it is hard-coded this way) so students will always have to instantiate a Dog class with the breed set to 'dalmation.' Otherwise test will fail.

  • Solution is to remove hard-coded breed 'dalmation'

View file extension should be index.html.erb and not index.erb

There's a test missing in the spec/controllers/application_controller_spec.rb file.

Hi. This lesson is really good, but I noticed that there was a test missing. There should be a test that checks for whether you can change the dog's breed. Something like this:

describe ApplicationController do
  describe 'Dog class' do
    ...
    # Maybe put this between the tests that check for changing the dog's name and age:
    it 'can change dog breed' do
      @dog = Dog.new("rudolph", "mastiff", 2)
      @dog.breed = "beagle"
      expect(@dog.breed).to eq("beagle")
    end
    ...
  end
end

Thanks as always for looking into this!

Sdcrouse

Lag

very slow loading.

Include Sample App Code

This repo includes code for a very basic sample app.

The README works entirely without that code. However, in theory, it'd be nice if this README included a working sample app and referenced it's source code within the README. We'd have to instruct the student to clone the lab and play and explore the local files as they go through the README.

needs content

Refer to Readme for content to be included

due 9/17/2015 - using content from other repos here

Dogs tests not hinted at or explained at all in the README.md

So this lab is really quite confusing. I created a Dog class as a model that inherited from model.rb... assuming that's what they were looking for... anyway I got the tests to pass, and when I looked at the solution code after submitting I saw that they created an @dog instance var to pass to the erb file from ApplicationController... but this is a poorly designed lesson. I have a little background in rails and MVC pattern so I figured they were looking for a model (though there is no test nor hint that they want to create an instance to pass to the view here)... some better wording is needed to explain this random request for a simple Dog class... at least a hint that it should be a model or something. I can imagine a lot of students being totally lost on this, or creating code that passes but doesn't necessarily serve the purpose of introducing the idea of passing data from a model to controller to view...

Tests fail if first defined test does not run first

The defined tests fail if the first defined test (it 'can create a dog with attributes on initialization') does not run first. If other tests run before this one there are leftover dogs in the DOGS array.
The easiest way to avoid the problem is to add the following line to the .rspec file:
--order defined

This makes sure the tests run in the order they have been defined in the spec and that the test suite passes (when the task has been solved correctly).

Refers to controller action that hasn't been mentioned yet.

Under subhead: "views directory":

"We've filled in the views for you to display the dog Ralph we just created in our controller action. Feel free to take a look."

Nothing of the sort has been filled out that I could find, and this is the first mention of Ralph. I Googled around and eventually figured out how to pass the last test on my own, but wasted a lot of time checking other lessons and trying to find these examples. Hadn't actually written any erb or incorporated MVCs at all to this point. Seems like the lesson's out of order or the order was changed at some point without the readme being updated to reflect that.

RPEC test inconsistent

application_controller_spec.rb

should read something like

it 'can change dog age' do
  @dog = Dog.new("rudolph", "mastiff", 2)
  @dog.age = 3
  expect(@dog.age).to eq(3)
end

currently reads

it 'can change dog age' do
  @dog = Dog.new("rudolph", "mastiff", 2)
  @dog. name = "bessie"
  expect(@dog.name).to eq("bessie")
end

a little unclear

so let me disclaim this by saying that most people finished with lab without a problem but some were really hung up. there are no instructions, is purely test-driven which is fine but they've only see the whole "set an instance variable in the controller and render it in a view" thing once or twice and i don't think it was every discussed explicitly (i could be wrong!). So would be good to provide some basic instructions/a reminder about that instance variable -> view set-up.

This lab is SO GOOD.

I usually flag issues with labs and lessons, but I just wanted to say this lab was really well done and the information in it is extremely helpful and easy to digest. Thank you!

rake (loadError) - Is this an error from my environment or part of the lesson to solve?

I honestly don't know if this is my fault but this works when I require 'rake' in my gemfile. I did run bundle install before issuing these commands. Is this a problem with my ruby environment setup?

12:38:31 activerecord-associations-intro
♥ rspec --fail-fast
/Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in require': cannot load such file -- rake (LoadError) from /Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in<top (required)>'
from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in require_relative' from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in<top (required)>'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in require' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inblock in requires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in each' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inrequires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:109:in block in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:ineach'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:21:inconfigure'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:101:in setup' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:88:inrun'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:73:in run' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:41:ininvoke'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/exe/rspec:4:in <top (required)>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:inload'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:in <main>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:ineval'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `

'
12:39:37 activerecord-associations-intro

♥ bundle exec rspec --fail-fast
/Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in require': cannot load such file -- rake (LoadError) from /Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in<top (required)>'
from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in require_relative' from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in<top (required)>'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in require' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inblock in requires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in each' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inrequires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:109:in block in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:ineach'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:21:inconfigure'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:101:in setup' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:88:inrun'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:73:in run' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:41:ininvoke'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/exe/rspec:4:in <top (required)>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:inload'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:in <main>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:ineval'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `

'
12:39:45 activerecord-associations-intro

/Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in require': cannot load such file -- rake (LoadError) from /Users/yonk/Development/code/foo/activerecord-associations-intro/config/environment.rb:5:in<top (required)>'
from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in require_relative' from /Users/yonk/Development/code/foo/activerecord-associations-intro/spec/spec_helper.rb:3:in<top (required)>'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in require' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inblock in requires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:in each' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration.rb:1280:inrequires='
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:109:in block in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:ineach'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:108:in process_options_into' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/configuration_options.rb:21:inconfigure'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:101:in setup' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:88:inrun'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:73:in run' from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/lib/rspec/core/runner.rb:41:ininvoke'
from /Users/yonk/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.3.0/exe/rspec:4:in <top (required)>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:inload'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/rspec:23:in <main>' from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:ineval'
from /Users/yonk/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `

'

♥ rvm -v
rvm 1.26.11 (latest) by Wayne E. Seguin [email protected], Michal Papis [email protected] [https://rvm.io/]
12:39:51 activerecord-associations-intro
♥ ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
12:39:56 activerecord-associations-intro

Test output changes each time rspec is run

The spec that tests Dog.all.count returns different output each time rspec is run. See example below.

Failures:

  1) ApplicationController Dog class can create a dog with attributes on initialization
     Failure/Error: expect(Dog.all.count).to eq (1)

       expected: 1
            got: 3

       (compared using ==)
     # ./spec/controllers/application_controller_spec.rb:7:in `block (3 levels) in <top (required)>'

Finished in 0.05782 seconds (files took 0.35458 seconds to load)
7 examples, 1 failure

Failed examples:

rspec ./spec/controllers/application_controller_spec.rb:5 # ApplicationController Dog class can create a dog with attributes on initialization

And once I run rspec again

Failures:

  1) ApplicationController Dog class can create a dog with attributes on initialization
     Failure/Error: expect(Dog.all.count).to eq (1)

       expected: 1
            got: 5

       (compared using ==)
     # ./spec/controllers/application_controller_spec.rb:7:in `block (3 levels) in <top (required)>'

Finished in 0.0462 seconds (files took 0.34495 seconds to load)
7 examples, 1 failure

Failed examples:

rspec ./spec/controllers/application_controller_spec.rb:5 # ApplicationController Dog class can create a dog with attributes on initialization

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.