Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Rails Girls LA Guide

rgla

Rails Girls LA 2016 Part 1 Rails 5


PART 2 | PART 3 | PART 4 | NOTES | SHARE YOUR PROJECT


Our App - L.A. Adventures

A bucket list for things to do in Los Angeles.
If you moved out of Los Angeles next month what are the places you wished you went to and the things you wish you did. Make a list of cool things to do so you can make a plan to do them in case you move someday. You don't want to have any regrets.

Our Goals

At the end of the day you should

  • Feel comfortable in the terminal
  • Have your project online
  • Be comfortable in git
  • Meet new friends to learn with
  • Find a mentor
  • Get resources to continue learning
  • Have Fun! <3

You should know

  • about ERB (Embeded Ruby) and how to use it
  • how to start a new Rails project
  • the difference between your local and remote code
  • what MVC means
  • what C.R.U.D. stands for and what it means
  • some markdown
  • about testing
  • how to add a gem to your project
  • about our friend Bundler

Share your sites at the end of the day:

https://gist.github.com/jendiamond/5a26b531e8e47b4aa638#file-tutorial_sharing-md

Kindness, Consideration and Respect.

  • Be kind to yourself. You are not less than anyone else because you do not know something.
  • Be considerate. Remember that all the coaches and organizers are happily volunteering their time to help you.
  • Respect others. Remember your coach is having patience with you so have patience with your student pair.

If you have any problems with anyone please let someone know. Code of Conduct


A Little Review to Start the Day

Go over the commandline prompts with your coach so you can be sure you can communicate clearly and easily throught the day.

Coach, your should read these aloud and have the students do them in their terminals

  • See what directory you are currently in pwd
  • Navigate to the Desktop directory cd
  • Create a new directory called rainbow mkdir rainbow
  • Change into the rainbow directory cd rainbow
  • Create a new directory in the rainbow directory called leprechaun mkdir leprechaun
  • Change into the leprechaun directory cd leprechaun
  • Create 3 files gold.md, nyancat.md & unicorn.md (in the terminal) touch gold.md nyancat.md unicorn.md
  • List the files in the leprechaun directory ls
  • Go into sublime and add a bit of text to the gold.md file subl .
  • Open the file in the terminal and read it cat gold.md
  • Delete the gold.md file from the leprechaun directory rm gold.md
  • Change back into the rainbow directory cd ../
  • Delete the rainbow directory rm -r rainbow
  • Find the flag to list all the hidden files man ls (ls -a)

Hooray for The Terminal Slide Show!

Psst - If you ever see a $ sign in this tutorial, it is not part of the code. The $ sign means that you should type the code that follows it into your terminal.


birds

Let us Dive into Rails

In the first section we are going to do a small amount of code but we will learn a lot about it.

We’re going to create a new Rails app called la_adventures

Open a terminal and create a new directory and navigate into that directory.

$ mkdir railsgirls
$ cd railsgirls

Verify that your directory is currently empty. ls -a

Generate a new rails app called la_adventures by running:
$ rails new la_adventures

This will create a new app in the la_adventures folder/directory.

Change into the la_adventures directory to get inside of our rails app.
$ cd la_adventures

Look at all the stuff you got from typing 3 small words. Check it out in your text editor.

The chart below is from the Railsbridge Intro to Rails tutorial

File/Folder Purpose
app/ Contains the controllers, models, and views for your application. You will do most of your work here.
config/ Configure your application's runtime rules, routes, database, and more.
db/ Shows your current database schema, as well as the database migrations.
public/ The only folder seen to the world as-is. If you put files in here, they will be served directly without any processing by Rails.
app/assets/ This is where your images, JavaScript, stylesheets (CSS), and other static files should go. Modern Rails apps use something called the Assets Pipeline, which combines all the JavaScript and CSS files in this directory into a single file for speediness.

Look at your New App in the browser

Start the rails server to see your new app by running:

$ rails server

  • rails server or rails s starts our local server in our terminal
  • ctrl+c shuts down our server if its active
  • ctrl+l clears the terminal screen. "clear" itself also works, unless we're in the rails command-line.

Open http://localhost:3000 in your browser.
You should see “Welcome aboard” page, which means that the generation of your new app worked correctly.
You may want to run a second terminal to have the rails server run continuously.

You are now running a server.

The WEBrick server. This is so you can see what your app will look like in production on the web. Notice that each time you add a new adventure or do anything inyour web site the server in your terminal shows a bunch of new stuff. If you look at it you can see what it is doing relates to what you are doing on the site. You should see something like this below:

=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server

When you are running the Rails server you cannot execute new commands.
If you try running cd or another command it will not work.
To return to the normal command prompt:

Type CTRL-C in the terminal to quit the server.


Local Version Control with Git

Before we do anything else lets create a local repository and save our new project to it. We will use a workflow for git that follows along these lines each time we commit. Hooray for TryGit!

Create a git repository by typing.

$ git init

Do each of these commands one at a time...

git status
git add .
git status
git commit -m 'Initial commit'
git status

This chart shows what each command means. This is your git workflow. Which means EVERY TIME we ask you to commit to git and GitHub in this tutorial you should follow these steps. It is a good habit to follow all these steps.

Your Git Workflow :)
git status Check status
git add . Add everything to the repository
git status Check status
git commit -m 'Your comment' Commit everything (-m means message)
git status Check status*

Again I will say, every time you commit, follow these steps. It's good practice and it will help you from getting messed up when things get more complex.
Where it says Your comment this is where you write in what you commit contains. It should note what you did. These comments are meant for you to remember what you did so make them very meaningful.
They are also public for everyone to read for ever. ;) A Note About Git Commit Messages

Remote Version Control with GitHub

Pushing to GitHub :)
Create a Github repository https://github.com
Add the remote host to your local git git remote add origin git@github.com:your_username/your_repository_name
Check your remotes git remote -v
Push commit to Github git push -u origin master

Coach: Discuss you git workflow.
https://youtu.be/IsvfofcIE1Q https://youtu.be/xnKhsTXoKCI

For the rest of the project you will only need to use the command git push origin master to push your changes to GitHub.


Update the README

We are going to use a DSL called Markdown to write our README file.
Look on GitHub at your current README File.
Note that it is a file in the list with all your other files but it is also shown at the bottom of your page so everyone can read it.
Markdown Documentation

First of all what is a DSL? - This is an acronym for Domain Specific Language. A DSL is a mini-language based on another. (Like Pig Latin.) A DSL uses a base language and abstracts it to have a particular functionality or make it simpler to write.

In Rails 5 the README is in markdown

If you are in an earlier version of Rails change the name of the README file from README.rdoc to README.md

Open the README.md in your text editor. This is now a markdown file. The .md suffix is for markdown. This guide is written in markdown. :) Markdown is a way to write HTML in a stripped down way.

Checkout Daring Fireball to learn more on how to use Markdown. (The Daring Fireball site is by John Gruber who wrote Markdown.)

Add the following to your README.md file:

    ## Rails Girls 2015 
    
    ---
    
    #### Ruby version 2.3.0
    #### Rails version 5.0.0.1

    ### L.A. Adventure App
    
    A bucket list for Los Angeles. This is a list of all the things I'd like to do in case I moved out of Los Angeles and never got to return. All the things I think about doing all the time but haven't made time to do yet.
    
    *Made by* **Your Name**  
    On 10-22-2016  
    
    My Coach: (your coach's name)  
    My Pair: (your coach's name)
    

Run your git workflow again to commit this change.

Commit from your home directory wherever you put it. Mine is here: $Desktop/railsgirls/la_adventures

Do each of these commands one at a time...
git status
git add .
git status
git commit -m 'Update the README'
git status
git push origin master

Each time you make a change you should commit it. Think, small commits.

Coach:

  • Show your students how to use Markdown on the commit you just pushed on GitHub.
  • Show how to create a gist in Github. You could put your notes for the day on a gist. More info.about Gists from GitHub.
  • Show your students some other README files from other GitHub repositories
    RSpec
    Bundler

$ rails generate

Create the Adventure scaffold

We’re going to use Rails’ scaffold functionality to generate a starting point that allows us to list, add, remove, edit, and view things.
In our case the scaffold and C.R.U.D. will let us:

  • Create a New Adventures (new / create)
  • Read about our Adventures (show) - List all our adventures (index)
  • Update / Edit our Adventures (edit / update
  • Delete our Adventures (destroy)

In Rails we call it C.R.U.D., the acronym for

Create
Read
Update
Destroy

We will be creating this in our database and you can imagine it looking a bit like this:

Adventures Table

 id        |   name    |  description  |  picture                   |  location    |  visit   

---------------|-----------|---------------|----------------------------|--------------|--------------
auto-generated | string | text | string | string | date 1 | "zoo" | "Animals!" |"http://tinyurl.com/zfq77mm"| 5333 Zoo Dr. | "2016-03-26"

Before we create the model...

Let's just peek in app/model
Note that there is no model there yet.
After we run the next command there will be an Adventure model. app/models/adventure.rb
( You can also peek at app/controllers and app/views.)


Type this in your terminal to create your first scaffold

$ rails generate scaffold adventure name:string description:text picture:string location:string visit:date

The scaffold creates new files in your project directory, but to get it to work properly we need to run a couple of other commands to update and create our Adventure database.

Active Record is the M in MVC It facilitates the use of your database.
Active Record uses some naming conventions.
Rails will pluralize your class names to find the respective database table.
So, for a class Adventure, you should have a database table called Adventure.

Note: You can run $ rails generate scaffold with no model name to get info and examples of a rails scaffold.

Let's look at a few things before we run the next command.

Let's look at the file that will be run when we type in
rake db:migrate    

Open the db/migrate/(date_time)_create_adventures.rb file. (Psst - (date_time) will be different in every app)

Notice that all the things that we just typed to create the scaffold are here in this file:

class CreateAdventures < ActiveRecord::Migration
  def change
    create_table :adventures do |t| 
      t.string :name
      t.text :description
      t.string :picture
      t.string :location
      t.date :visit
       
      t.timestamps null: false
    end 
  end 
end

Let us also peek in the db directory.
The file that the database table will be in is called schema.db
Note that there is no schema.db there yet.
Once we run rake db:migrate it will be created from the migration file.

Now you can run this command in your terminal. This will run the migration file

db/migrate/(date_time)_create_adventures.rb

rake db:migrate

Note: In Rails 5 you can run $ rails db:migrate

Restart your server and check out your app. (You have to restart your server when you run rake db:migrate)

Open http://localhost:3000/adventures in your browser.

rails server

Your new app might not look like much but it is awesome.

(For now your image will only be a string. We will make it an image later in the guide.)

Play around with your new app.

  • Create some new adventures.
  • Delete some.
  • List them all.
  • Create some more.
  • See what the C.R.U.D. is all about.
Started GET "/adventures/2" for 33.33.33.1 at 2016-02-26 01:48:33 +0000
Cannot render console from 33.33.33.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by AdventuresController#show as HTML
  Parameters: {"id"=>"2"}
  Adventure Load (3.1ms)  SELECT  "adventures".* FROM "adventures" WHERE "adventures"."id" = ? LIMIT 1  [["id", 2]]
  Rendered adventures/show.html.erb within layouts/application (4.0ms)
Completed 200 OK in 109ms (Views: 103.0ms | ActiveRecord: 3.1ms)

Discuss

  • Rails scaffolding Rails scaffolding is a quick way to generate some of the major pieces of an application. If you want to create the models, views, and controllers for a new resource in a single operation, scaffolding is the tool for the job.
    http://stackoverflow.com/questions/6735468/why-do-ruby-on-rails-professionals-not-use-scaffolding
  • What exactly is happening in the command rails generate scaffold adventure name:string description:text picture:string visit:date
  • MVC Model View Controller Model (ActiveRecord ) It maintains the relationship between the objects and the database and handles validation, association, transactions, and more.

This subsystem is implemented in ActiveRecord library, which provides an interface and binding between the tables in a relational database and the Ruby program code that manipulates database records. Ruby method names are automatically generated from the field names of database tables.

View ( ActionView ) It is a presentation of data in a particular format like html or json, triggered by a controller's decision to present the data.

This subsystem is implemented in ActionView library, which is an Embedded Ruby (ERb) based system for defining presentation templates for data presentation.

Controller ( ActionController ) The facility within the application that directs traffic, like, querying the models for specific data, or, organizing that data (searching, sorting, messaging it) into a form that fits the needs of a given view.

This subsystem is implemented in ActionController, which is a data broker sitting between ActiveRecord (the database interface) and ActionView (the presentation engine).

  • Look at the model name and related database table and the controller for it
  • Naming conventions - singular in the model - plural in the controller - CapitalizedCamelCase Classes
  • What are migrations and why do you need them?
  • What is Rake?

All of our adventures are stored in our database. This is where we get into the MVC or the Model View Controller aspect of our application.

How did all those pages get created and hooked together?

The Rails scaffold did it for you.

The following explanation is from the Railsbridge Intro to Rails tutorial

(Psst -You should try this tutorial on your own after this workshop. It is excellent! Sarah Mei and Sara Allen are responsible for creating Rails Bridge which inspired the creation of Rails Girls which is why you are here today. If you ever meet these women shake their hand vigorously and thank them.)
Also you should know the names Linda Liukas and Karri Saarinen who founded Rails Girls and are awesome! :)

Let's take a closer look at some of the files Rails created:

app/models/adventure.rb

This file contains code for our adventure model. If you look at it, it's nearly blank. Creating, reading, updating, and deleting records are built into Rails.

app/views/adventures

This folder contains all the views for our adventures model. This is where the code for the forms you used above is stored. Rails created all of these pages as part of the scaffold. If you've written HTML before, many lines in the views should look familiar. Rails views are HTML with some extra code added to display data from the database. Yay Dash tutorial!

app/views/adventures/index.html.erb

This is the code for the page that lists all the adventures. Index is the name given to the "default" page for a web site or a section of a web site. When you navigate to http://localhost:3000/adventures the adventures index page is what is sent to your computer.

app/views/adventures/show.html.erb

This is the page you get when you click the "Show" link on the "Listing adventures" page.

app/views/adventures/new.html.erb

This is the page you get when you click "New Adventure".

app/views/adventures/edit.html.erb

This is the page you get when you click "Edit".

app/views/adventures/_form.html.erb

You may have noticed that the page for new adventures and the page to edit adventures looked similar. That's because they both use the code from this file to show a form. This file is called a partial since it only contains code for part of a page. Partials always have filenames starting with an underscore character.

Challenge question: Can you find the line of code in new.html.erb and edit.html.erb that makes the form partial appear?

app/controllers/adventures_controller.rb

This is the controller file that Rails created as part of the scaffold If you look you'll see a method (a line beginning with def) for each of the views listed above (except _form.html.erb)


Routing

You may have noticed that the first page of your application still shows the “Welcome aboard” page. Let’s make it go straight to the Adventures page.

Open config/routes.rb and after the first line add

root 'adventures#index'

Test the change by opening the root path http://localhost:3000 in your browser.

Rails routing configurations are kept in config/routes.rb file.
http://guides.rubyonrails.org/routing.html

  • When your Rails application receives an incoming request for: GET /adventures/17
  • In the form of a URL, for us right now it is http://localhost:3000//adventures/17
  • GET /adventures/17 asks the router to match it to a controller action.
  • Our router reads: resources :adventures This includes all the CRUD actions
    Create Read Update Destroy
  • The request is dispatched to the adventures controller's show action with { id: '17' } in params.

adventures_controller.rb

  def show
    @adventure = Adventure.find(params[:id])
  end

The code above defines the method show, a.k.a the controller action show,

  • it assigns the instance variable @adventure to the adventure which is in the url
  • so if we were at http://localhost:300/adventures/3
  • then we would view the page for the adventure with the id of 3
    Look at the `rake routes below:
    adventure | GET| /adventures/:id(.:format) | adventures#show

Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as GET, POST, PATCH, PUT and DELETE. Each method is a request to perform an operation on the resource. A resource route maps a number of related requests to actions in a single controller.

Coach: Run $ rake routes, and discuss it a bit.

Prefix Verb URI Pattern Controller#Action
      root | GET    | /                              | adventures#index
adventures | GET    | /adventures(.:format)          | adventures#index  
           | POST   | /adventures(.:format)          | adventures#create  

new_adventure | GET | /adventures/new(.:format) | adventures#new
edit_adventure | GET | /adventures/:id/edit(.:format) | adventures#edit
adventure | GET| /adventures/:id(.:format) | adventures#show
| PATCH | /adventures/:id(.:format) | adventures#update
| PUT | /adventures/:id(.:format) | adventures#update
| DELETE | /adventures/:id(.:format) | adventures#destroy


Deploy to Herouku

http://guides.railsgirls.com/heroku

We are now going to put our app on the internet.
First you have to
Run your git workflow again to commit all changes.
Your message this time should be 'Add Adventure scaffold, Update routes to show Adventure on home page'

Because we are going to deploy our app to Heroku we need to update our Gemfile.
Why? Well, because we are using a Sqlite3 database and Heroku uses a Postgres database.
That's completely alright.
The Sqlite3 database easily transfers to the postgress data bases.
Luckily Rails has multiple environments Development, Production and Test.

  • The Development environment is where you develop your app.
  • The Production environment is what you "push to production" / Heroku or whatever server you use.
  • The Test environment is for testing.

Push to Heroku

Before we push to Heroku we need to do two things

  1. Move Sqlite3 into the production environment
  2. Add Postres to the production environment

The third thing you need to do if you are not in Rails 5 3. Add the Rails 12 factor gem to the Gemfile

Open your Gemfile. Find gem 'sqlite3'

We are going do two of our tasks to move it into the development environment. Then we are going to have the production environment use postgres.
(Heroku uses postres which is why we are adding it.)

Your Gemfile should look something like this:

There may be other gems in your production or development groups. That is okay.
There will also be a lot of comments. You can keep them or delete the. It's up to you. They are interesting to read.

Gemfile

source 'https://rubygems.org'


gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'sqlite3'
gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'carrierwave', '~> 0.10.0'

gem 'jquery-rails'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'

group :development, :test do
  gem 'byebug', platform: :mri
end

group :development do
  gem 'web-console'
  gem 'listen', '~> 3.0.5'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

===

A good practice is to always add your Ruby version to the Gemdile.

Under source 'https://rubygems.org' in your Gemfile

Add: `ruby '2.3.0'

===

Notice the groups :development and :production

There are three environments in Rails

  • development - This is where you develop your code
  • production - This is the code you push to a server like Heroku
  • test - This is where you test your code

===

We are going do two tasks at the same time

  1. Move Sqlite3 into the production environment gem 'sqlite3'
  2. Add Postres to the production environment gem 'pg' to move it into the development environment.

We are going to have the production environment use PostgresSQL which is a database.
Heroku uses Postres which is why we are adding it. If you don't add it,

1. Delete the gem 'sqlite3' that is already in your Gemfile

===

2. Add this in your Gemfile at the bottom. This adds the Postgres gem.

group :production do
  gem 'pg'
end

So your Gemfile looks like this:

source 'https://rubygems.org'

gem 'rails', '4.2.5'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc

group :development, :test do
  gem 'byebug'
end

group :development do
  gem 'web-console', '~> 2.0'
  gem 'spring'
  gem 'sqlite3'
end

group :production do
  gem 'pg'
end

Notice the words do and end means this is a block of code that belongs together.
All the gems you want to be ONLY in the development group need to be in between the do and end of the development block.

There are other gems that are outside of these groups. That is okay too. They are available to all the groups.

More about groups by Yahuda Katz.

Then run this in your terminal to setup your dependencies:

$ bundle install --without production

If you run bundle install later, without any flags, bundler will remember that you last called bundle install --without production.

Coach: - Discuss why you run bundle install and what the Gemfile.lock is doing.

If heroku is not running you may need to install the heroku toolbelt.

===

If you are not running Rails 5 you have to do a third step.

Add Rails_12factor

This gem was incorporated into Rails 5 so you don't need it. Unless you are converting a Rails 4 app to Rails 5.

The Rails_12factor gem makes our app available on Heroku.

This gem modifies the way Rails works to suit Heroku, for example Logging is updated and the configuration for static assets (your images, stylesheets and javascript files) is tweaked to work properly within Heroku’s systems.
https://github.com/heroku/rails_12factor/blob/master/README.md
https://github.com/heroku/rails_12factor/issues/3

Please change the following in the Gemfile:

group :production do
  gem 'pg'
end

to

group :production do
  gem 'pg'
  gem 'rails_12factor'
end

Then run bundle install in your terminal.

$ bundle

Your Gemfile should now look like this:

source 'https://rubygems.org'

gem 'rails', '4.2.5'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc

group :development, :test do
  gem 'byebug'
end

group :development do
  gem 'web-console', '~> 2.0'
  gem 'spring'
  gem 'sqlite3'
end

group :production do
  gem 'pg'
  gem 'rails_12factor'
end

Run your git workflow again to commit all changes and push to Heroku.

Your comment should be 'Add Postgres'

===

To get more information on why this change is needed and how to configure your app to run Postgres locally, see why you cannot use Sqlite3 on Heroku.

===

Deploying your App

Read this all first and discuss it and then we'll do these two commands.

In your terminal type:

heroku create

Then type:

git push heroku master

We need to create our Heroku app by typing heroku create in the terminal and see something like this:

Creating sheltered-refuge-6377... done, stack is cedar
http://sheltered-refuge-6377.herokuapp.com/ | git@heroku.com:sheltered-refuge-6377.git
Git remote heroku added

In this case “sheltered-refuge-6377” is your app name.

Pushing the code

Next we need to push our code to heroku by typing git push heroku master. You’ll see push output like the following:

Initializing repository, done.
Counting objects: 101, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (91/91), done.
Writing objects: 100% (101/101), 22.68 KiB | 0 bytes/s, done.
Total 101 (delta 6), reused 0 (delta 0)

-----> Ruby app detected
-----> Compiling Ruby/Rails
-----> Using Ruby version: ruby-2.0.0
-----> Installing dependencies using 1.6.3
       Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4    --deployment
       Fetching gem metadata from https://rubygems.org/..........
    ...
-----> Launching... done, v6
       http://sheltered-refuge-6377.herokuapp.com/ deployed to Heroku

You’ll know the app is done being pushed, when you see the “Launching…” text like above.

Migrate database

Next we need to migrate our database like we did locally:

Run this command in your terminal:**

$ heroku run rake db:migrate

===

View Your App!

In a browser got to http://sheltered-refuge-6377.herokuapp.com/ (except put the name of your app in there instead of sheltered-refuge-6377.)

You can also type heroku open in the terminal to visit the page.

Heroku’s platform is not without its quirks. Applications run on Heroku live within an ephermeral environment — this means that (except for information stored in your database) any files created by your application will disappear if it restarts which is why it takes so long to spin up when you first go to the site.

Obviously this doesn’t seem to be useful if you were running a real life application, but there are ways to work around this which is commonly used by a lot of popular websites.


Take a break

Stretch.
Walk around the block.
Notice that there are other people in the room.
Don't skip taking breaks and being away from the computer.
Regular breaks allow you to go longer and learn more.

Relax


Proceed onward to Part 2 :)

Rails Girls LA 2016 Part 2

I hope you are ready to roll again and make some more cool changes to your new site. This is where it really starts to look like something cool and you will start to see the potential of Rails.

Coach:

  • Make a plan with your students as to which of the next few sections you want to concentrate on. You have a limited amount of time together and there is a lot of material here.
  • It might be a good idea to start woiekung in branches from here on.

In this section there are directions to:


Adding Photos

Photo Album

We need to install a piece of software to let us upload files in Rails.

Open the Gemfile in the project directory using your text editor.
In the main section (not in production or development) add the carrierwave gem.
Carrierwave Documentation

gem 'carrierwave'

Coach: Explain what libraries (Gems) are and why they are useful. Describe what open source software is.

In the terminal run:

$ bundle

Now we can generate the code for handling uploads.

In the terminal run:

$ rails generate uploader Picture

===

Open app/models/adventure.rb

Under the line

class Adventure < ActiveRecord::Base

Add mount_uploader :picture, PictureUploader

class Adventure < ApplicationRecord
  mount_uploader :picture, PictureUploader
end

===

Open app/views/adventures/_form.html.erb

Change this:

<%= f.text_field :picture %>

to this:

<%= f.file_field :picture %>

Sometimes, you might get a TypeError: can’t cast ActionDispatch::Http::UploadedFile to string. If this happens, in file app/views/adventures/_form.html.erb change the line

<%= form_for(@adventure) do |f| %>

to

<%= form_for @adventure, :html => {:multipart => true} do |f| %>

Add this line to your config/application.rb file: config.autoload_paths += %W(#{config.root}/app/uploaders)

require_relative 'boot'
require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module LaAdventures1016
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/app/uploaders)
  end
end

===

In your local browser, add a new adventure with a picture. When you upload a picture it doesn’t show up as a picture because your program is only telling the computer to show the path to the file. Let’s fix that.

Open app/views/adventures/show.html.erb

Change this:

<%= @adventure.picture %>

to this:

<%= image_tag(@adventure.picture_url, :width => 600) if @adventure.picture.present? %>

Re-start your rails server now. (CTRL-C to stop it from running)

$ rails s

YAY!

Run your git workflow again to commit all changes.

Coach: Talk about Embedded Ruby. Show them what the embedded ruby looks like when you "Inspect Element" in the browser. And the difference between <% example %> and <%= example %> and sometimes <%= example -%>

Embedded Ruby is mixed in with our HTML. It is Ruby code.
How does the server know what to execute as Ruby and what to serve up as HTML?
There are a few ways to do this, but for our project (and many Rails projects) we use <%= RUBY CODE HERE %> to tell the server when we're using Ruby code.
The server executes this code as Ruby code and then embeds it in the existing HTML.


Design & Bootstrap

The app doesn’t look very nice yet. Let’s do something about that. We’ll use the Twitter Bootstrap project to give us nicer styling really easily. Yay, HTML/CSS tutorial. :)

Coach:

  • Make a plan with your students. Time box how long you want to spend on styling. Stick to it. There is a lot more to learn.
  • Discuss what Boostrap is and does.
  • Talk a little about CSS and layouts.
  • Talk about the relationship between HTML and Rails. What part of views is HTML and what is Embedded Ruby (ERB)?
  • How does MVC relate to this? (Models and controllers are responsible for generating the HTML views.)
  • There are four methods of adding CSS to HTML
    1. Link to a separate CSS file
    2. Embed CSS into the HTML
    3. Add Inline CSS to HTML tags
    4. Import a CSS file from within CSS

Note: The pictures you uploaded before as strings will not be images now. They will still be Strings.
If you want the images to persist after you go off line you will have to download the photos to your computer and add them to your app/assets/images file. Or you have to use the CarrierWave gem or AWS to store the images for you because Heroku will not automatically store them.

===

Add the stylesheets

We are using an external stylesheet called <link rel="stylesheet" href="//railsgirls.com/assets/bootstrap.css">.
Check out what it looks like.

Note: If your internet isn't connected you won't be able to see it. You could copy this and include it in your own site. Ask your coach how you would do that.

Open app/views/layouts/application.html.erb in your text editor and above the line

 <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>

Add this:

<link rel="stylesheet" href="//railsgirls.com/assets/bootstrap.css">
<link rel="stylesheet" href="//railsgirls.com/assets/bootstrap-theme.css">

And replace this

<%= yield %>

with this:

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

===

Let’s add a navigation bar and footer to the layout.

In the same file, app/views/layouts/application.html.erb Add this:

<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="/">The L.A. Adventure App</a>
    </div>
    <div class="collapse navbar-collapse">
      <ul class="nav navbar-nav">
        <li class="active"><a href="/adventures">Adventures</a></li>
        <li ><%= link_to 'New Adventure', new_adventure_path %></li>
      </ul>
    </div>
  </div>
</nav>

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

<footer>
  <div class="container">
    Rails Girls 2015
  </div>
</footer>
<script src="//railsgirls.com/assets/bootstrap.js">

Note: Notice the <nav> section is at the top and the <footer> section is at the bottom. Also notice the javascript we added <script src="//railsgirls.com/assets/bootstrap.js"> Check out what it looks like.

===

Let’s change the styling of the Adventures table (the adventures/index page)

Open app/assets/stylesheets/application.css

**At the bottom of all the other code add

body {
  padding-top: 60px;
}

table,td,th {
  vertical-align: middle;
  border: none;
}

th {
  border-bottom: 1px solid #DDD;
}

footer {
  margin-top: 100px;
  text-align: center;
  color: #999;
}

Save your files and refresh the browser to see what was changed.

===

Adjust the application layout

Open app/assets/stylesheets/application.css

Replace the line:

body { 
  padding-top: 100px;
}

with this line:

body { 
  padding-top: 60px;
  }

Delete the file app/assets/stylesheets/scaffolds.css.scss

We don’t need the default stylesheet generated by Rails so we can delete it.
When you run rails g scaffold Rails creates a bunch of files for you. You could have just created them yourself. Rails just knows what files you probably want and where to put them.
The cool thing is that when you go to another Rails application it will look a lot like this one, well the files will be in the same places anyway.
The word generate means to produce something or cause something to be produced.

===

Refine the navigation

Refresh your page at http://localhost:3000/. You will not find much change but it’s good preparation for the following steps.

Considering “adventure” is the most important object in your app, we are going to put the “New Adventure” button on the navigation bar to make it always available.

Open app/views/layouts/application.html.erb

Under the line:

<li class="active"><a href="/adventures">Adventures</a></li>

Add this line:

<li ><%= link_to 'New Adventure', new_adventure_path %></li>

===

Design the Adventures List

It’s time to make the Adventure list page look professional. For that, we are going to replace the table layout with a div layout.

Coach: Talk a little about table versus div.

Open app/views/adventures/index.html.erb

Replace all lines with this:

    <h1>Adventures</h1>

    <% @adventures.in_groups_of(3) do |group| %>
      <div class="row">
        <% group.compact.each do |adventure| %>
          <div class="col-md-4">
            <%= image_tag adventure.picture_url, width: '100%' if adventure.picture.present?%>
            <h4><%= link_to adventure.name, adventure %></h4>
            <%= adventure.description %>
          </div>
        <% end %>
      </div>
    <% end %>

Coach: Explain what the new code means line by line, and talk a little about grid layouts.

Look at you web page now! We get a nice looking adventure list.

Click the “New Adventure” button, and create more adventures with real text and pretty pictures - the page will look much better with content. There is a principle of contemporary web design: content is the best decoration.

===

Design the Adventure details page

When you click the title of an adventure, you will be brought to the details (show) page of the adventure.
It needs some styling. Let’s make it beautiful.

Open app/views/adventures/show.html.erb

Replace all lines with this:

    <p id="notice"><%= notice %></p>

    <div class="row">
      <div class="col-md-9">
        <%= image_tag(@adventure.picture_url, width: '100%') if @adventure.picture.present? %>
      </div>
    
          <div class="col-md-3">
        <p><b>Name: </b><%= @adventure.name %></p>
        <p><b>Description: </b><%= @adventure.description %></p>
        <p>
          <%= link_to 'Edit', edit_adventure_path(@adventure) %> |
          <%= link_to 'Destroy', @adventure, data: { confirm: 'Are you sure?' }, method: :delete %> |
          <%= link_to 'Back', adventures_path %>
        </p>
      </div>
    </div>

Run your git workflow again to commit all changes.

Push to GitHub

Push to Heroku


Create an Info Page

Info

Lets add a static page to our app that will hold information about the author of this application — you!

$ rails generate controller pages info

This command will:

  • Create a new directory (folder) in app/views called /pages
  • Create a file called info.html.erb This will be your info page.
  • Adds a route to your config/routes.rb
get "pages/info"

===

Open the file app/views/pages/info.html.erb

Add information about your app:

<h1>L.A. Adventures</h1>
<h2>A bucket list for things to do in Los Angeles</h2>

<p>If you moved out of Los Angeles next month what are the places you wished you went to and the things you wish you did.  Make a list of cool things to do so you can make a plan to do them in case you move someday. You don't want to have any regrets.</p>

Let's create out first partial

The word partial means existing only in part; incomplete. We are going to take the code for the navbar and put it in a file of its own. It is only part of the page, thus it is called a partial. You can put anyrhing into a partial and then call it in the body of the views although if you have too many partials it can slow down your app's performance. Navbars and footer are perfect for partials.
A partial is always named with an underscore in fromt of it. _navbar.html.erb

Create a file called: app/layouts/_navbar.html.erb

Put the entire section from the app/views/layouts/application.html.erb in it:

    <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/">The L.A. Adventure App</a>
        </div>
        <div class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="/adventures">Adventures</a></li>
            <li ><%= link_to 'New Adventure', new_adventure_path %></li>
          </ul>
        </div>
      </div>
    </nav>

In it's place, we instead call it with the method render using Embedded Ruby.

app/views/layouts/application.html.erb

<%= render "layouts/navbar" %>

===

While we are here you can do the same thing to your footer.

===

Add a link in the navbar to get to your Info page:

Open the file app/views/pages/info.html.erb

To view your new info page, take your browser to http://localhost:3000/pages/info

Add <li><a href="/pages/info">Info</a></li>

<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="/">The L.A. Adventure App</a>
    </div>
    <div class="collapse navbar-collapse">
      <ul class="nav navbar-nav">
        <li class="active"><a href="/adventures">Adventures</a></li>
        <li><%= link_to 'New Adventure', new_adventure_path %></li>
        <li><a href="/pages/info">Info</a></li>
      </ul>
    </div>
  </div>
</nav>

Add RSpec-Rails for Testing

Add this gem in your group :development, :test do section of your Gemfile

Gemfile

group :development, :test do
  gem 'byebug'
  gem 'rspec-rails', '~> 3.4', '>= 3.4.2'
end

===

$ bundle

You may have to run bundle update.

===

Running the next command will install all the files you'll need for testing in RSpec

$ rails generate rspec:install

===

We are going to use Request Specs for our tests. Request specs only check for the status code and the response but this allows us to see that our views, controllers and models are all working.

Create a new directory called requests The create a file in it called adventures_spec.rb
Because your added _specs at the end of the file Rails and RSpec will recognize it as a test.

spec/requests/adventures_spec.rb

require 'rails_helper'

#------------------INDEX

describe "adventures", type: :request do
  let!(:adventure) { FactoryGirl.create(:adventure) }
  describe 'reading adventures' do
    it "should render adventures index template" do
      get '/adventures'
      expect(response).to have_http_status(200)
      expect(response).to render_template :index
    end
  end

#------------------NEW/CREATE

  describe 'GET /adventures/new' do
    it "should render adventures new template" do
      get '/adventures/new'
      expect(response).to have_http_status(200)
      expect(response).to render_template :new
    end
  end

  describe 'POST /adventures' do
    it 'should create a new adventure' do
      expect {
        post '/adventures', adventure: { date_time: adventure.date_time,
                                     activity: adventure.activity,
                                     location: adventure.location,
                                     description: adventure.description }
      }.to change(adventure, :count).by(1)
      expect(response).to have_http_status(302)
      expect(response).to redirect_to(adventure_url(adventure.last.id))
    end
  end


#-----NEW/CREATE FAILURE

  describe 'GET /adventures/:id save failure' do
    before do
        post '/adventures', adventure: { location: adventure.location,
                                     description: adventure.description }
    end
    it 'should not render adventure show template' do
      get "/adventures/#{adventure.last.id}"
      expect(response).to have_http_status(200)
      expect(response).to render_template :show
    end

    it 'does not save the new adventure' do
      expect{
        post '/adventures', adventure: { location: adventure.location,
                                     description: adventure.description }
      }.to_not change(adventure,:count)
    end
    
    it 're-renders the new page' do
      post '/adventures', adventure: { location: adventure.location,
                                   description: adventure.description }
      expect(response).to render_template :new
    end
  end

#------------------SHOW

  describe 'GET /adventures/:id' do
    before do
      post '/adventures', adventure: { date_time: adventure.date_time,
                                   activity: adventure.activity,
                                   location: adventure.location,
                                   description: adventure.description }
    end

    it "should render adventure show template" do
      get "/adventures/#{adventure.last.id}"
      expect(response).to have_http_status(200)
      expect(response).to render_template :show
    end
  end

#------------------EDIT/UPDATE

  describe 'GET /adventures/:id/edit' do
    it "should render adventures edit template" do
      get "/adventures/#{adventure.id}/edit"
      expect(response).to have_http_status(200)
      expect(response).to render_template :edit
    end
  end

  describe 'POST /adventures/:id' do
    before do
      post '/adventures', adventure: { date_time: adventure.date_time,
                                   activity: adventure.activity,
                                   location: adventure.location,
                                   description: adventure.description }
    end

    it "should update a adventure" do
      expect {
        patch "/adventures/#{adventure.id}", adventure: { date_time: adventure.date_time,
                                   activity: adventure.activity,
                                   location: adventure.location,
                                   description: adventure.description }
      }.to change(adventure, :count).by(0)
      expect(response).to have_http_status(302)
      expect(response).to redirect_to(adventure_url(adventure))
    end
  end

#-----EDIT/UPDATE FAILURE

  describe 'GET /adventures/:id/edit failure' do
    before do
      post '/adventures', adventure: { date_time: adventure.date_time,
                                   activity: adventure.activity,
                                   location: adventure.location,
                                   description: adventure.description }
    end

    it 're-renders the edit page' do
      get "/adventures/#{adventure.last.id}/edit", adventure: { date_time: adventure.date_time,
                                  activity: adventure.activity,
                                  location: adventure.location,
                                  description: adventure.description }
      expect(response).to render_template :edit
    end
  end

#------------------DELETE

  describe 'DELETE' do
    before do
      post '/adventures', adventure: { date_time: adventure.date_time,
                                   activity: adventure.activity,
                                   location: adventure.location,
                                   description: adventure.description }
    end

    it "should delete a adventure" do
      expect {
        delete "/adventures/#{adventure.last.id}"
      }.to change(adventure, :count).by(-1)
      expect(response).to have_http_status(302)
    end
  end

end

Run your tests

Run your tests in the terminal
$ bundle exec rspec spec

This is the basis of you tests. They are all not passing. Figure out why.

===

Coach:
Talk about googling terminal output (errors), the Rails Api, Stack Overflow.

The Given When Then testing sequence:

  • (Given) some context
  • (When) some action is carried out
  • (Then) a particular set of observable consequences should obtain

http://guide.agilealliance.org/guide/gwt.html#sthash.QBJBFFby.dpuf
http://martinfowler.com/bliki/GivenWhenThen.html


Make the Tests Pass by adding Add Factory Girl

Add FactoryGirl-Rails & Ffaker for Testing

Gemfile

gem 'factory_girl_rails', '~> 4.5'
gem 'ffaker', '~> 2.2'
Configure your test suite - ?To Ad or not to Add?

spec/support/factory_girl.rb

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

===

spec/factories/adventures.rb

FactoryGirl.define do
  factory :adventure do
    date_time { Date.today.strftime("%A, %B %d %I:%M %P") }
    activity { FFaker::Sport.name }
    location { FFaker::AddressUS.neighborhood }
    description { FFaker::HipsterIpsum.words(4).join(',') }
  end
end

auto-generated:

FactoryGirl.define do
  factory :adventure do
    date "2016-03-02"
    time "2016-03-02 18:09:47"
    activity "MyString"
    location "MyString"
    description "MyText"
  end
end

Create Routes and View for Index

config/routes.rb

Rails.application.routes.draw do
  resources :adventures, only: index
  root "adventures#index'
end

Awesome

Rails Girls LA 2016 Part 3

If you are still going strong and want to do more to your app this section has tutorials to:

  • Allow People to Comment on the Adventures
  • Add a Map
  • Add Star Rating

Allow People to Comment on the Adventures

Create a comment scaffold, with the commentator name, the comment body (contents of the comment) and with the reference to the adventures table (adventure_id).

In your terminal generate another scaffold.

$ rails g scaffold comment user_name:string body:text adventure_id:integer

This will create a migration file that lets your database know about the new comments table.

Run the migrations

$ rake db:migrate

Add relations to models

You need to make sure that Rails knows the relation between objects (adventures and comments). As one adventure can have many comments we need to make sure the adventure model knows that.

Open app/models/adventure.rb and after the row

class Adventure < ActiveRecord::Base`

Add

has_many :comments

The Comment also has to know that it belongs to an adventure.

Open app/models/comment.rb

After

class Comment < ActiveRecord::Base

Add the row

belongs_to :adventure

Render the comment form and existing comments

Open app/views/adventures/show.html.erb

After the image_tag

    <%= image_tag(@adventure.picture_url, :width => 600) if @adventure.picture.present? %>

Add

<h3>Comments</h3>
  <% @comments.each do |comment| %>
    <div>
      <strong><%= comment.user_name %></strong>
      <br />
      <p><%= comment.body %></p>
      <p><%= link_to 'Delete', comment_path(comment), method: :delete, data: { confirm: 'Are you sure?' } %></p>
    </div>
  <% end %>
<%= render 'comments/form' %>

In app/controllers/adventures_controller.rb

Add to show action after the row

@adventure = Adventure.find(params[:id])

this

@comments = @adventure.comments.all
@comment = @adventure.comments.build

Open app/views/comments/_form.html.erb

After

<div class="field">
  <%= f.label :body %><br />
  <%= f.text_area :body %>
</div>

add the row

<%= f.hidden_field :adventure_id %>

And remove

<div class="field">
  <%= f.label :adventure_id %><br>
  <%= f.number_field :adventure_id %>
</div>

Go check it out in your local view.

View an adventure.You should see a form for adding a comment as well as deleting old comments.

HiYah!


Add a Map

We are going to setup a map feature that will allow you to see all your adventures on a map and search for adventures by address.

First let’s setup our migrations

Setup an address column

In your command line, generate the migrations for address, latitutde and longitude.

$ rails generate migration AddAddressToAdventures address:string

$ rails generate migration AddLatitudeAndLongitudeToAdventures latitude:float longitude:float

Then run your migrations.

$ rake db:migrate

Then, add address field to form. We will setup our app so we only need to input an address and not coordinates.

app/views/adventures/_form.html.erb

  <div class="field">
    <%= f.label :address %><br>
    <%= f.text_field :address %>
  </div>

Because we’ve added new attributes to our form, we need to permit them in our params in our controller. Add address attribute to the permitted params of adventures_controller.

**app/controllers/adventures_controller.rb**

 def adventure_params
    params.require(:adventure).permit(:name, :description, :picture, :visit, :address)
 end

Let’s also add in our map attributes to our adventures/page

app/views/adventures/show.html.erb

    <p><b>Name: </b><%= @adventure.name %></p>
    <p><b>Description: </b><%= @adventure.description %></p>
   + <p><b>Address: </b><%= @adventure.address %></p>
    + <p><b>Latitude: </b><%= @adventure.latitude %></p>
    + <p><b>Longitude: </b><%= @adventure.longitude %></p>

Now create a new adventure and add in an address. You’ll know it works when you see the the coordinates of your address on your show page.

Setting up geocoder

Now let’s setup our geocoder gem. Geocoder is an excellent gem for converting addresses and coordinates, finding nearby locations and determining distances.

In your Gemfile add

#Gemfile
gem 'geocoder'

Bundle in your command line

$ bundle install


Setup your adventure model for geocoder

app/models/adventure.rb

class Adventure < ActiveRecord::Base
+ geocoded_by :address   
+ after_validation :geocode          # this command auto fetches our coordinates
  mount_uploader :picture, PictureUploader
  has_many :comments
end

Setting up gmaps4rails

The gmaps4rails gem allows us to use google maps with our own custom overlays (markers, infowindows).

Add gmaps4rails to your gemfile

Gemfile

gem 'gmaps4rails'

and bundle again in your command line

$ bundle install

Adding a map section to your app

Create a new file in your views/pages directory called map.html.erb.

You will need to add scripts that connect with Google’s map API and a div that holds the map. Add in the code below to that map file. You can change the size of the map by messing with the width and height on the <div id=map.

views/pages/map.html.erb

<div style='width: 800px;'>
  <div id="map" style='width: 800px; height: 400px;'></div> 
</div>

<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=&region="></script>

<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>

<script type="text/javascript">
  var handler = Gmaps.build('Google');
  handler.buildMap({ internal: {id: 'custom_style'}, provider: {}, internal: {id: 'map'}}, function(){
    markers = handler.addMarkers(<%=raw @hash.to_json %>);
    handler.bounds.extendWith(markers);
    handler.fitMapToBounds();
  });
</script>

For this to work, we need underscoreJS.
Go to http://underscorejs.org/ and click on production version(1.8.3). Copy everything in that file.

Create a new file in vendor/assets/javascripts directory called underscore.js.

Paste the code in vendor/assets/javascripts/underscore.js


Next, setup your javascript by requiring underscore and gmaps/google in your application.js

We need to do this so our javascript can see those gems.

app/assets/javascript/application.js

+ //= require underscore
+ //= require gmaps/google
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

Whenever we add to our application.js file, we should restart our server to see those changes.

In the command line, restart your server.


Next, we’ll fix up our controller. Add in a map method to pages_controller to incorporate the map.

#app/controllers/pages_controller.rb
```ruby
  def map
    if params[:search].present?
      @adventures = Adventure.near(params[:search], 1000, :order => :address)
    else
      @adventures = Adventure.all
    end
    @hash = Gmaps4rails.build_markers(@adventures) do |adventure, marker|
      marker.lat adventure.latitude
      marker.lng adventure.longitude
      marker.infowindow adventure.name
      marker.picture({
        "width" => 32,
        "height" => 32})
      marker.json({ name: adventure.name})
    end
  end

Add static maps and nearby locations in the adventures/show page. The image tag shows a static map and the nearby locations will find all the nearby locations of the address you entered in a 1000 mile radius.

views/adventures/show.html.erb

<%= image_tag "http://maps.google.com/maps/api/staticmap?size=450x300&sensor=false&zoom=16&markers=#{@adventure.latitude}%2C#{@adventure.longitude}" %>

<h3>Nearby Adventures</h3>
<ul>
<% for location in @adventure.nearbys(10) %>
  <li><%= link_to location.address, location %> (<%= location.distance.round(2) %> miles)</li>
<% end %>
</ul>

Go to one of your adventure#show pages to see your map and nearby locations.


Adding a search field

Finally, let’s add a search input feature to your views which allows you to enter an address or location name, and will get the nearest adventures to that inputted area.

#app/views/pages/map.html.erb

<%= form_tag adventures_path, :method => :get do %>
  <p>
    <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "Search Near", :name => nil %>
  </p>
<% end %>

And there you have it. Try creating a few more adventures to populate your map.

Map!


Challenge:

Figure out how to Add star rating and write the tutorial for it

Star Rating

https://rubygems.org/gems/jquery-star-rating-rails
http://www.rubydoc.info/gems/jquery-star-rating-rails/4.0.4
http://www.fyneworks.com/jquery/star-rating/
https://rubygems.org/
https://www.ruby-toolbox.com


Awesome

Rails Girls LA 2016 Part 4

AWS- Setting up Carrierwave for S3

It's time to setup your AWS bucket so your photos can persist on the internet. Instead of pushing photos to your local machine, you will be pushing them to an Amazon Web Service cloud.

You will need your credit card for doing this. It's free to use but be forewarned, be careful not to push your AWS credentials up to any public domains or somebody could use your credit card.

Before we begin let's get our app setup for Amazon Web Services(AWS):

Adding Fog Gem and Carrierwave Configs

The fog gem is the Ruby cloud services library that helps you send your pictures to your AWS account. This will let the images show up every time you go to your site.

To install, add fog-aws to your Gemfile

#Gemfile
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
gem 'carrierwave'
+ gem 'fog-aws', '~> 0.7.6'

In your command line, bundle install

$ bundle install

Make a new file in config/initializers directory called carrierwave.rb and add configurations. This is the file that carrierwave will use to push your photos to AWS.

# config/initializers/carrierwave.rb

require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.root = Rails.root.join('tmp')
  config.cache_dir = 'carrierwave'
  
  config.fog_credentials = {
    :provider               => 'AWS',
    :aws_access_key_id      => ENV["AWS_ACCESS_KEY"],
    :aws_secret_access_key  => ENV["AWS_SECRET_KEY"]
  }
  config.fog_directory  = ENV["AWS_BUCKET"]
end

Change your storage setting in your app/uploaders/picture_uploader.rb file by uncommenting storage :fog and commenting out storage file

# app/uploaders/picture_uploader.rb

class PictureUploader < CarrierWave::Uploader::Base
  +storage :fog
  #storage :file
end

Lastly, create a new file called fog.rb in the lib directory and add a fog module to get the fog-aws gem working.

# lib/fog.rb

module Fog
  # :)
end

##Setting up Amazon S3

Now, let's setup our Amazon S3 bucket by first creating an account on aws.amazon.com.

Do the sign up procedure.

After you've finished that let's setup our user and bucket.

Create a user

Click on 'security and credentials' under your name in the top right of the navbar.

Click 'continue to security credentials' on the pop up.

Click on 'User' in the left side bar and then create a new user.

  1. Enter any username you want
  2. Leave the 'generate an access key for each user' checked
  3. And press create button

You should then see: Your 1 User(s) have been created successfully. This is the last time these User security credentials will be available for download.

===

At the botton of the page, press download your credentials. We will use these credentials later to connect our app with AWS.

Next click on 'close'. You should see the user you just created in your table. Click on that user.

Select the 'permissions' tab and click on 'attach policy'. Give the user administrative access (should be the first option).

Click on 'attach policy' to finish.

####Create an s3 bucket

Click on the “Services” button in the top left corner in the navbar and click 's3' from the dropdown menu. (all the way to the right)

Press 'create bucket'.

Enter a unique name for your bucket and the region you are in. Click 'create'. (You will need your bucket name later so remember it)

Currently your bucket is empty but later on they will be filled with the images that you uploaded from your app.

###More app setup

THIS IS IMPORTANT!

We need to setup Figaro gem to allow you to securely enter your AWS credentials in your rails application. It will hide your AWS credentials from the public.

Add figaro to your Gemfile

#Gemfile

gem 'fog-aws'
+ gem 'figaro', '~> 1.1', '>= 1.1.1'

On your command line bundle install and install figaro setup

$ bundle install

$ bundle exec figaro install

The bundle exec figaro install command will generate an application.yml file and add that file to your .gitignore. Any file declared in .gitignore will not be pushed up to github.

Check if the application.yml file was added to your .gitignore. It should have this code at the bottom of the .gitignore.

#.gitignore

# Ignore application configuration
/config/application.yml

To set up figaro for heroku, enter this command in the command line

$ figaro heroku:set -e production

Adding your AWS credentials to your app

Next it's time to open up your previously downloaded credentials from AWS and insert those credentials into your newly generated application.yml. You can delete all the commented code from the application.yml file first if you like. Then, paste in this code.

# config/application.yml

AWS_ACCESS_KEY: paste-aws-access-key-here
AWS_SECRET_KEY: paste-aws-secret-key-here
AWS_BUCKET: enter-your-bucket-name-here  #if you don't remember your bucket name, look back to the AWS site

Go through your git flow git status git add . git status git commit -m 'Add persist image feature' git status

Restart your server

Go to your localhost:3000/adventures/new and add an image to your app. Afterwards, check your s3 bucket to see if your image is inside. If it is, everything is working.


Adding your AWS credentials to heroku

For Heroku setup, go to your heroku app on www.heroku.com. In the settings of your app, click on 'reveal config vars' and add your aws credentials to the table one by one.

# Key             #Value
AWS_ACCESS_KEY | access-key-here
AWS_SECRET_KEY | aws-secret-key-here
AWS_BUCKET  | bucket-name-here

Finally, in the command line push your app to heroku

$ git push heroku master

and add a new picture. If it's all working, your picture should still be there a few hours later. Check your s3 bucket to see if your image is inside. If it is, everything is working


if you get an error with bin.rails

try deleting code in bin/rails and adding this code

# bin/rails

#!/usr/bin/env ruby
begin
  load File.expand_path("../spring", __FILE__)
rescue LoadError => e
  raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'

Creating the app

mkdir railsgirls  
cd railsgirls  
rails new la_adventures  
cd la_adventures

git workflow

git init  
git status  
git add .  
git status  
git commit -m 'Initial commit'  
git status

Add a GitHub remote repository

git remote add origin   
git@github.com:your_username/your_repository_name  
git remote -v  
git push -u origin master

Generate the scaffold

rails generate scaffold adventure name:string description:text picture:string visit:date  
rake db:migrate

Set up the route to have the opening page be the Adventures index
config/routes.rb
root 'adventures#index'

app/controllers/adventures_controller.rb

  def show
    @adventure = Adventure.find(params[:id])
  end

Gemfile

source 'https://rubygems.org'

gem 'rails', '4.2.5'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc

group :development, :test do
  gem 'byebug'
end

group :development do
  gem 'web-console', '~> 2.0'
  gem 'spring'
  gem 'sqlite3'
end

group :production do
  gem 'pg'
  gem 'rails_12factor'
end
@lindsay
lindsay commented Apr 18, 2015

:octocat: Lindsay St John :octocat:

Email lindsaysj@github.com
Twitter @lindsaysjvb9
GitHub @lindsaysj
My Coach: Joshua Loper
My Pair: Shanah Zilberkweit
My New Website: http://lindsaysf.herokuapp.com/adventures

@ShanahZ
ShanahZ commented Apr 18, 2015

Shanah Zilberkweit

Email: shanahz@github.com
:octocat: @shanahz
My coach: Joshua Loper
My pair: Lindsay St John
My website: https://railsgirlsberlin.herokuapp.com/

Thank you for organizing such a great event! 💻 💡

@aein
aein commented Apr 19, 2015

Aein Hope

Email: aein@github.com
Twitter: @aein
GitHub: @aein
My Coach: @claudiob
My Pair: @lailavinson
My New Website: https://railsgirl-la-adventures.herokuapp.com/

@danadanadana

Email: dana@citrusstudios.com
Twitter: @danaismyname
GitHub: @danadanadana
My Coach: Valerie Woolard
My Pair: Laura !
My New Website: http://dana-rails-girls-la-adventure.herokuapp.com/

Yay!

@mixophrygian

Eleanor Weigert

Email: eweigert@gmail.com
Twitter: @EleanorClarinet
GitHub: @mixophrygian
My website: https://eleanors-la-adventures.herokuapp.com/

Thanks for hosting this wonderful day!

@aundriab

Can you please update the README section? It's unclear that the 'xxx.rdoc' is the old, and should be updated to the newer markdown version 'xxx.md'.

@Reltre
Reltre commented Oct 24, 2015

@jendiamond

The spec_helper.rb file needs two lines of code added to it to make tests run correctly:

ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)

In the testing section, adventure.title is used instead of adventure.name

Also, it might be good to add that some people may beed to run rake db:test:prepare after a migration to have their testing db up to date.

@patriciarealini

Here are some updated instructions for installing rspec:


Test your App with RSpec

http://guides.railsgirls.com/testing-rspec/

Install rspec

For starters, let’s install RSpec and all of its dependencies.

rspec ruby documentation

Please change the following in the Gemfile:

Find group :development, :test do & add

gem 'rspec-rails'

Then run this in your terminal:

bundle
@austinrfnd

@jendiamond cleaned up the rspec portion on my fork of the gist: https://gist.github.com/austinrfnd/32112bb0e6d3337e0877

@machikoyasuda

Nitrous.io GitHub instructions to add SSH key are here: https://community.nitrous.io/docs/connect-to-github

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment