Done with One Month Rails: A Summary

Today I finished up the One Month Rails course in exactly 15 days.  I was basically a Weekend Warrior, in that I didn’t work on this much during the work week.  I think it was a substantial course and worth the $20 that I paid for access to it.

Pros:

+  Getting me setup with an environment, deploying to Git and Heroku was probably the best part about this.  Compared to Codecademy or other such sites, this course actually got me started on the path to making a real app and showing it to the world within the very first lesson.  That is a huge motivator to keep going, and also gave me essential knowledge that I need to start app #2.
+ His teaching was slow and his voice is calming and his delivery is great.  I like how he explained why we’re doing everything.
+ I feel like I have a solid knowledge of searching the web for answers to things and importing gems that might be useful to my project.
+ I got a brief glimpse into Ruby syntax, though I don’t necessarily understand it yet.
+ I have a working app at the end that is basically Pinterest minus the boards that I can show to people.  This is exciting.

Con:

+ I don’t think it taught me how to code, at all.  It taught me the basics of creating an app with Rails and how to edit/modify things.  I feel like I could build any number of apps and I could probably Google for the code snippets required to add just about any functionality.  Do I feel that would make me a “Rails developer”?  No.  I don’t really understand how to write any Ruby code.

I liked this course. It gave me the knowledge that I need to start making another app, once I come up with an idea.

My next steps:

Do the Ruby course at CodeSchool and Codecademy so that I can understand the syntax of that language better.  Read Why’s Poignant Guide to Ruby.  Then, I’ll do Michael Hartl’s Rails tutorial.  After that, I’m going to build something and this will give me time to figure out exactly what. =)

Advertisements

Uploading images with my Rails pinterest-esque site

First thing, I needed Image Magick, which I got by typing in Terminal:

$ brew install imagemagick

I already had Homebrew installed from following some other tutorial, which is why it worked so smoothly.  Next, I’m going to install the Paperclip gem, a popular gem for image uploading.  I just need to open up my gemfile and add

gem "paperclip", "~> 3.0"

in the top section. I run “bundle” in Terminal and it downloads and installs Paperclip.  The first thing to do to get started is to run the following:

$ rails generate paperclip pin image

In that command, ‘pin’ is the name of the model, and ‘image’ is what we want to call the type of file people are uploading.  When we run this, it generates a migration so we have to run rake db:migrate like usual.  Next we have to open up the pin.rb model and make a few adjustments.  Basically we need to make :image accessible, and then validate the attachment in a number of ways: presence, filetype and image size.  Here is the new code:

class Pin < ActiveRecord::Base
  attr_accessible :description, :image

  validates :description, presence: true
  validates :user_id, presence: true
  validates_attachment :image, presence: true, 
  											content_type: { content_type: ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']},
  											size: { less than: 5.megabytes }

  belongs_to :user
  has_attached_file :image
end

Now we update the view.  This is a piece of cake.  Just add <%= f.input :image, label: “Upload an image” %> above the description in the _form.html file.  Also in this file, I need to add notifications for the other validations that we just set in the previous part. I add this under the other notification:

  <%= f.full_error :image_file_size, class: "alert alert-error" %>
  <%= f.full_error :image_content_type, class: "alert alert-error" %>

Now we have to update the show view.  Above the description I add: <%= image_tag @pin.image %>.  And we have to update the index view.  So first in the index.html we add another column header by doing      <th>Image</th>.  And then, in the _pin.html partial we put in <td><%= image_tag pin.image %></td>.  Now it works!

The problem is, the image I uploaded (of my horse Rosie) is too big.  Apparently Paperclip has image styles to help us with that.  In pin.rb model change the has_attached_file line to:

has_attached_file :image, styles: { medium: "320x240>"}

And then in my pin.html file I change the image_tag pin.image part to:

<%= image_tag pin.image(:medium) %>

Since this all happens during processing, it will only happen when the image is uploaded.  I reuploaded and now this looks awesome.  These are saved into the public folder of our application under a new folder called System.  We probably want to add this stuff into our .gitignore because we don’t want the images we’re playing around with to end up pushing live.  I opened up the .gitignore file and added this to the bottom:

#ignore paperclip uploaded files
/public/system

And now, holy crap, I have a running Pinterest style website with image uploading live on Heroku!

Screen Shot 2013-04-04 at 12.45.08 AM

Associating pins with users

Now I have this site where people can upload pins, which are just descriptions right now but will eventually also be image uploads.  The only problem is that they’re not associated with users, so it’s just one giant repository of pins with no attribution.  Time to fix that!

First thing, I’m being introduced to the Rails console.  How exciting. =)   I access this by entering ‘rails console’ in Terminal, which changes me to be in the Rails environment.  I can now type in Ruby code, like say, math, and it will work.  This will be useful because it will help me see the guts of my application in ways that the views will not.  Like, I can access the models that we have created (pins and users).  In each of those models, there is a class at the top of the file which is something I can specifically access via the console.

Like for example, since the class for user is User, I can enter User.all in the console and it will show me:

User Load (0.2ms) SELECT "users".* FROM "users"
=> [#<User id: 1, email: "test.user@me.com", encrypted_password: "$2a$10$ezCykZohTGcirSq.NfBBBOiE5TEU24vpQ1GWuEblX7xT...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 7, current_sign_in_at: "2013-04-01 00:48:53", last_sign_in_at: "2013-04-01 00:43:44", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2013-04-01 00:03:51", updated_at: "2013-04-01 00:54:05", name: "Tami Baribeau">

Hey, that’s me!  I could also do Pin.all and that gives me the info you’d expect it to.  So now we’re finally digging into the meat of all of this, which is really helpful for someone like me who wants to not just know HOW to do things but also why they’re doing what they’re doing.

Basically, in the pins controller it created a number of actions automatically.  My index, show, new, create, update, and destroy.  Each of those things has a respond_to block which basically created an API for us for free by using json format to give us access to all this infoz.  This is a bonus of running a scaffold.

Let’s just look at the index action:

  def index
    @pins = Pin.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @pins }
    end
  end

Ignoring the respond_to part and just looking at the first line.  @pins is the variable that was created, and it’s being set to the Pin.all, the same method I ran in the Rails console.  So basically, the first thing being called when I load up that index page (at http://localhost:3000/pins) is the Pin.all command, which is why all the pins show on that page.  The @ sign makes it a global variable, giving us access to it throughout the entire application.  We need it to be a global variable so that our VIEW has access to it.  Makes total sense!

Now we’re moving on to the show action.  It looks like this:

@pin = Pin.find(params[:id])

Basically, I can do Pin.find(1) in the rails console and it will give me back the details for only the Pin with the ID 1.  Basically in the show action, it’s getting the ID parameter from the URL when I click on ‘show’ on a specific pin.  So that’s how that works.

So now we’ll establish the connection between a user and a pin.  The first thing to do is update our pin item.  I need to add a user_id to each database record, so in Terminal I have to run;

rails generate migration AddUserIdToPins user_id:integer:index

I made up AddUserIdToPins, apparently that doesn’t have to be anything specific.  I still don’t understand how it knows which database to modify.  What if I had two?  In fact, I DO have two…pins and users right?  I r confused.  Adding index told it that someday I’d want to be searching by that value.  After that I have to create the migration and then run rake db:migrate.   I then can’t immediately see the new column, I have to shut down the Rails console with ctrl-d and then open it back up…I can run @pin = Pin.last and see that my database has a user_id attribute although it is nil.

Now we need to establish that users have pins and pins have a user.  To do this we go inside our Models folder.  Inside of the user.rb model, at the end I add:

has_many :pins

Under the pin.rb file, at the end I add:

belongs_to :user

This is one example of a specific association, but more of them can be found here.

So now, we have other things we can do in Rails console (after we restart it again with Ctrl-D). I can now do Pin.last and then Pin.user and it will give me the user id of the last Pin that was entered.  It’s nil right now because we haven’t saved any pins with user ids yet.  I could also do User.last to get the last user, and then User.pins which would show me all of their pins with some fancy SQL action.

So how do we associate a pin with a user when it’s created?  When you click “new pin”, we’ll want to make sure it’s saving the ID of the person who is creating the pin to the pin itself.  But first we should require them to be logged in to access the new pin page.  To do this we add this to the top of our pins controller:

before_filter :authenticate_user!, except: [:index]

The authenticate_user! part of this is something that Devise gives us.  This is telling us that before running any of the actions on the page, make sure the user is logged in.  Except in the case of the index page which allows people to see all the pins.

So now we know someone will be logged in when they create a new pin, which is essential to saving their ID when the pin is created. 😉   We need to edit both the “new” action and the “create action”.    In the “new” action, Rails gives us an easy way to do this.  Instead of:

@pin = Pin.new

I’m going to do:

@pin = current_user.pins.new

Likewise, in the “create” action we change:

@pin = Pin.new(params[:pin])

to:

@pin = current_user.pins.new(params[:pin])

Now it’s saving user_id in the database which is great, but I can still edit other user’s pins which is no bueno.    I gotta change my “edit” action from:

@pin = Pin.find(params[:id)

to:

@pin = current_user.pins.find(params[:id)

And I do the same thing in update and destroy, naturally.

Next, since we have a user associated with each pin, we can show a user’s name when they’re on the page of their pin.  That’s easy, I just open the “show” view and then add  <%= @pin.user.name %> under the description part.  I wanted to delete the previous pins because they don’t have users and therefore generate ugly errors when I try to hit their show page, so I just do Pin.first.delete a couple times.

Now every pin I make in the future should have a user id associated with it, but just in case I’m going to open my pin.rb model and add:

validates :user_id, presence: true

Now we want to make sure the edit and destroy buttons only show up for the person who owns the pin.  So we open our _pin partial view (since that’s what the index is rendering somehow…even though it doesn’t have the same name and I’m still fucking confused about that).  I need to wrap the “edit” and “destroy” links inside a check like so:

 
<% if current_user == pin.user %>
    blahblah
<% end %>

Gotta do the same thing on my “show” page too to hide the “edit” link.  Easy peasy.

There you have it.  Next up, uploading images! 🙂

Setting up the first ‘pins’ on my Rails site

The application that I am making with this One Month Rails tutorial is a Pinterest-style site where people can upload images.  This project is about actually starting the pinning feature.

So far, I’ve only worked with models when using Devise.  But that didn’t actually require me to create my own model, so that’s what I’m going to work on now.  Apparently you need to add a resource, which is done by running a scaffolding.  Bare with me here. 🙂  To run the scaffolding I needed to start out with:

$ rails generate scaffold Pins description:string --skip-stylesheets  #where Pins is the name I chose

The reason I include description:string is because in my Pinterest-like site, I’m going to want to allow people to upload a description along with each one of their images.  I use the –skip-stylesheets parameter because normally scaffolds come with a stylesheet by default but I don’t need one since I am using Bootstrap.  If I had forgotten to put the skip stylesheets stuff, I should just delete app/assets/stylesheets/scaffolds.css.scss and start anew.

After running this, it created a Controller (pins-controller), it created a model, and a bunch of views.  It also makes a migration because we need to add the pins to the database.  Which is why next we’ll have to run:

$ rake db:migrate

Holy crap.  Now when I go to http://localhost:3000/pins it looks like this:

Screen Shot 2013-04-03 at 8.17.18 PM

The “new pin” feature actually works, at least for descriptions!  That seems pretty crazy, and I have no idea how that just worked.  Limitation of this tutorial is that it didn’t explain to me what just happened.  I’m pretty technical-minded so I’d appreciate if it told me more about what was going on behind the scenes.  As an experiment I tried making another scaffolding named “Stuffs” just to see if the name “Pins” had anything to do with it knowing I wanted a feature created that allows people to upload descriptions.  Alas, Stuffs displayed the same exact functionality. So, yeah.  Neat.

Okay, I listened to more of the tutorial and I guess resources come with basically 4 different actions.  You can create a pin, read a pin, update a pin, and destroy a pin.  People remember this using the CRUD acronym.  So anytime I create a scaffolding, I’m telling the system what it is that I want to be able to create, read, use, and destroy.  Makes sense!

Next I want to edit that description field, because the field is so small and what if people want to upload a whole paragraph about their pin?   To do this, I go to my views under the Pins folder and I looked at my new.html.erb which shows that I’m using a form that is being referenced somewhere: <%= render ‘form’ %>.  This means I can edit this form in the _form.html.erb file.   I edit the description field which looks like this originally:

<%= f.input :description %>

And I make it look like this:

<%= f.input :description, as: :text, input_html: {rows: "3" } %>

This makes it so that there are 3 rows instead of just the standard 1 row.  I also want to change the form to the horizontal view that I did in previous forms, which is done at the top of the _form.html.erb file by changing:

<%= simple_form_for(@pin) do |f| %>

to:

<%= simple_form_for(@pin, html: { class: "form-horizontal"}) do |f| %>

And I want my button to look like all the other buttons on my site (the bootstrap style) so I do this:

<%= f.button :submit, class: "btn btn-primary" %>

And for some reason (which he doesn’t tell me) I don’t need the form-inputs div class so I delete this:

<div class="form-inputs">

and it’s associated </div>.

Next we want to make the Show page look a bit better, because it’s awfully blank and boring. I open up the show.html.erb file and get rid of the <p id=”notice”><%= notice %></p> at the top because it’s a flash and I already have the Bootstrap flash being used in my layouts folder, in the application.erb file.  I guess that is sitewide?

I put the top section in a row div, and then a span (column) 6 which is a reference to the Bootstrap grid system.  I also offset it by 3 so that it moves the description in a bit.  I did this by  putting in <div class=”span6 offset3″>.

Next I’m adding a “well” which is a Bootstrap feature.  I put this div around the same description box with <div class=”well”>.  A well looks like this:

Screen Shot 2013-04-03 at 8.48.22 PM

That looks better.  I also learned that the main page for my pins (at http://localhost:3000/pins) is called the index action, because it’s indexing all the pins that have been submitted.  If I click “Show” on any of those pins, the URL changes to append the ID of the pin.  Even though I never told my site that I wanted pins to have IDs, it automatically adds one to any item in a model.  Since Devise added a user model, it’s doing the same thing for users too.  Rails just does that for free, along with adding a ‘create date’ and a ‘last updated’ field to all the items as well.

Now, the list of pins (the table) is a bit ugly, so we’re going to update that. The very first thing we can do is add a table class of ‘striped’ within index.html.erb (under the pins view) so that it gives the table an instant Bootstrappy look.  Next, we wrap the table header (where it says Description) with <thead> and the actual pins list under <tbody>. This makes the top actually look like a header:

Screen Shot 2013-04-03 at 9.48.04 PM

Next we want to do what’s called a partial, which I did before.  Basically, I’m taking everything between the  <% @pins.each do |pin| %> section out of this file and putting it into its own view. (which i’m naming _pin.html.erb.  I then delete that bit of Ruby code and replace it with:  <% render @pins %>.  Nothing changes when I refresh my page, which is exactly what I wanted.  I’m kind of confused on why that works though.  Since my file name was _pin in the singular, why does render @pins work?  I have no idea.

Next I want to make sure to validate the form submitted so that no one can submit an empty pin.  To do this, we create a validation by opening up the pin.rb model and adding validates :description, presence: true in the pin class.  There are a number of other validations I could have used instead of in addition, such as length.  A list of these validations is here.

So, that’s it for this lesson!

User database with Devise and the simple form gem

Up until now, my simple website has had ‘login’ and ‘logout’ buttons but they haven’t actually been functional because there is no concept of a database setup yet.  The two videos I watched today helped me not only install the Devise gem to add database functionality to my site, but also use the simple form gem to make my forms look good and match Bootstrap.

Screen Shot 2013-03-31 at 6.37.10 PM

I don’t know that it makes sense to walk through these because the help documentation for both of those gems was pretty easy to follow but there were a couple of things I want to make sure I remember.

The first is that for simple_form, I needed to use the –bootstrap modifier to get the version I needed that works with Bootstrap.

Also, here is what I had to do to make the forms look good:

At the top of the edit.html.erb and new.html.erb files, I had to  change form_for to simple_form_for.  I also had to add the class form-horizontal, so now the code at the top looks like this:

<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { class: 'form-horizontal'}) do |f| %>

Next I had to get rid of all long mumbo jumbo for the fields and simplified them with f.input.  This makes it look like:

<%= f.input :name %>
<%= f.input :email %>
<%= f.input :password %>
<%= f.input :password_confirmation %>

Finally, I had to change the <div> in front of the buttons to   <div class= “form-actions”> and add class: ‘btn btn-primary’  to all of the buttons.  This makes it look like so:

<div class= "form-actions"><%= f.submit "Sign up", class: 'btn btn-primary' %></div>
<% end %>

The other thing is that Devise’s notifications aren’t very attractive out of the box, so to switch to Bootstrap’s notifications I had to do <%= f.error_notification %> at the top instead of Devise notifications.

Deploying to Heroku for the first time with Devise:

I need to remember to run this in Terminal otherwise none of the user functionality will work: heroku run rake db:migrate.

Adding user fields to my project with Devise:

First I have to run in Terminal:

$ rails generate migration AddNameToUsers name:string

then

$ rake db migrate

In app => models => user.rb I need to make my new “name” field accessible, so I add it to the attr_accessible block of code.

Next I have to actually ASK the user for their name, so I go to new.html.erb and add in <%= f.input :name %> there.  And of course I’d have to do that in the edit_registration file too, but that’s kind of self-explanatory.

The only other thing I did was make ‘members only content’ which I did by using some Ruby code <% if user_signed_in? %>. That code on my homepage looks like:

<% if user_signed_in? %>
<h1>Congrats, you're logged in!</h1>
<% else %>
<div class='hero-unit'>
<h1>Welcome to One Month Rails!</h1>
<p>
You found the homepage for the <%= link_to "One Month Rails", "http://onemonthrails.com" %> application.
</p>
<p>
<%= link_to "Sign Up Now!", new_user_registration_path, class: "btn btn-primary btn-large" %>
</p>
</div>
<% end %>

My application is live here now:

http://young-basin-3485.herokuapp.com/

Though right now, you can just sign up, login, edit your registration.  There isn’t a whole lot of anything up there, but apparently I’ll be making a type of simple Pinterest soon starting with the very next lesson in One Month Rails. 🙂

The post in which I discover Bootstrap

So, now I have this little website but it’s pretty barebones and ugly and now I’m just super excited when the instructor tells me that it’s time to improve the look and feel.  Apparently we’re going to do that with a little Gem called Bootstrap that was started by two guys from Twitter and has changed the way people style websites forever. I’ve already heard from a few people that it’s a good way to make a website that “looks like every other site” but as long as it’s a starting place, I’m happy.  Plus, this course taught me how to use the bootstrap sass gem to make some extra scss modifications to make my site look a little bit different.

To add bootstrap-sass I just needed to add this into my Gemfile (in the project root folder).

  gem 'bootstrap-sass', '~> 2.2.2.0'

After you add that to the gemfile, you have to tell the project to install that particular gem by running this in Terminal:

$ bundle install

After that, you have to restart your server otherwise the new bundled gems won’t work.  You can quit out of it and then enter ‘rails server’ in Terminal to do that.

Now, I have the bootstrap bundle installed but I’m not actually using it in my project.  To start using it I have to go into my app/assets/stylesheets/styles.css.scss file and add the following lines:

@import 'bootstrap';
@import 'bootstrap-responsive';

Next in app/assets/javascripts/application.js I need to actually make sure to require bootstrap.  I add the bolded line in the location below:

.
.
.
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .

Then, we started styling. Most of this was all done by looking at code snippets on the Bootstrap website.  The first thing we did was put some of the content on the front page into a container so that it separates it from the rest of the site and looks good.  This was done by going into app/views/layouts/application.html.erb and adding <div class=”container”> around my <%= yield %> section.  Like so:

.
<div class="container">
    <%= yield %>
    <%= render 'layouts/footer' %>
</div>
.
Next I added a navbar in the app/views/layouts/_header.html.erb file:
<div class="navbar navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </a>
             <a class="brand" href="/">OMRails</a>

                <div class="nav-collapse">
                    <ul class="nav">
                        <li>
                            <%= link_to 'Home',  root_path %>
                        </li>
                        <li>    
                            <%= link_to 'About',  about_path %>
                        </li>
                    </ul>
                    <ul class="nav pull-right">
                                <li><%= link_to 'Login',  '#' %></li>
                    </ul>
                </div>
        </div>
    </div>
</div>

Next we added some colors to app/assets/stylesheets/styles.css.scss like making the footer text gray, changing the navbar background, and removing the shadow below the navbar:

$navbarBackgroundHighlight: white;
$navbarBackground: white;
$btnPrimaryBackground: purple;

@import 'bootstrap';
body{
    padding-top: 60px;
}

@import 'bootstrap-responsive';

.navbar-inner{
    @include box-shadow(none !important);
    border: 0;
}

.footer{
    margin-top: 50px;
    color: $grayLight;
    a{
        color: $gray;
    }
}

Lastly, we added one of those fancy “Hero Units” that just about every website on the internet has nowadays.  All I had to do was wrap my home page text in:

<div class="center hero-unit"> INSERT HOME PAGE TEXT HERE
</div>

Finally, I saved and uploaded to Git and Heroku.  Voila!

git add .
git commit -am 'Add Bootstrap'
git push
git push heroku master
 This was a lot of fun because it started to give me the building blocks I need with Bootstrap to build neat things.  It looks like Bootstrap is pretty capable and should be a fun way to learn by trial and error which is exactly what I need in order to teach myself. 🙂

 

 

 

Creating Pages in Rails

The starter site that I created and uploaded is just a default root page with no additional pages. It’s not much of a website yet. ^_^  The next class in One Month Rails had me creating pages and learning how to set one as root.  It also created a navigation bar that allowed me to go from one page to another.  It was a little difficult to understand at first because I’m used to just clicking “new post” on some various GUI to get new pages to appear.  But it made sense after a little bit of noodling. 🙂

How to set up the first page:

$ rails generate controller Pages home  # Create a Pages controller with a home action
$ rm public/index.html # public/index.html will automatically override any root route set

It was still important to set up that new Home page that I created above to make it the root page when my site is first loaded.  This is done in the /config/routes.rb file by adding the following:

root :to => 'pages#home'

I also added another page there by doing:

get 'about' => 'pages#about'

However, that won’t really work because there isn’t an about page actually created yet.  Creating the page was as easy as making a new file, about.html.erb in app/views/pages.  

Both pages have to also be in the controller, otherwise they won’t be controlled, I guess.

class PagesController < ApplicationController
  def home
  end

  def about
  end
end

 I also learned about the applications.html.erb file which apparently is called by every page on the site and comes along with every Rails project.  The only thing that actually changes what content is shown on each page is the <%= yield %> section.  Originally, I edited this file to put the HTML content for my header and footer, but then the course had me create two separate files for these under app/views/layouts called _header.html.erb and _footer.html.erb.  Then, instead of actually typing out all their contents in the applications.html.erb file, I used ‘render’ to pull these things in above (for the header) and below (for the footer) the <%= yield %> section.  Here’s the code for how to render contents from another file in the project:

<%= render 'layouts/footer' %>
<%= render 'layouts/header' %>

Linking to another page:

Here is the syntax:

<%= link_to "Home", root_path %>
<%= link_to "About", about_path %>

So that was it for my page!  I also ended up with pushing it up to Git and Heroku so I could see it live in the world.