I’m still here!

Long time no talk.  Real life happened and things have been crazy around here so I took a break from writing on this blog.

When I last blogged here, I was trying out Team Treehouse.  I’m still slowly working my way through it though I have to be honest that I’m not an enormous fan of it.  I mean, what it’s trying to teach me is fine but I’m finding that the quiz and code snippets way of learning just doesn’t teach me the ‘hows and whys’.  I just basically cram for the tests and then forget all the knowledge.  Also, the videos are SO CHEESY.  At first I found it charming but now I’m just irritated with it all.

I switched now to doing Michael Hartl’s Ruby on Rails Tutorial and I’m loving it so far.  It’s teaching me way more about the way things work.  In fact, it’s basically like the Skillshare One Month Rails course that I was doing before, except more in-depth.  I’m feeling like I’m actually learning with it instead of just going through the motions and following tutorial steps.

I’m struggling to come up with a project idea that I want to make to test my application of my knowledge.  I have a few small ideas but nothing I’m really excited to build.  Once I get a good idea I know I’ll run with it and charge ahead, but it’s the ideas I’m struggling with right now.

Anyway, back to the Rails tutorial. 🙂

Advertisements

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!

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.