Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

Could a video instructor (or genius altruist!) please discuss my understanding of the treebook system?

This is a huge post, but I'd like to think my monthly fee covers any personal help you can give me regarding the islands! :) Hopefully this will be a help to others as well

Routing root to: 'statuses#index' means that when a browser requests the root url of the your rails application, rails goes to the statuses controller.

The statuses controller:

class StatusesController < ApplicationController
  before_filter :authenticate_user!, only: [:new, :create]

  # GET /statuses
  # GET /statuses.json
  def index
    @statuses = Status.all

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

  # GET /statuses/1
  # GET /statuses/1.json
  def show
    @status = Status.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @status }
    end
  end

  # GET /statuses/new
  # GET /statuses/new.json
  def new
    @status = Status.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @status }
    end
  end

  # GET /statuses/1/edit
  def edit
    @status = Status.find(params[:id])
  end

  # POST /statuses
  # POST /statuses.json
  def create
    @status = Status.new(params[:status])

    respond_to do |format|
      if @status.save
        format.html { redirect_to @status, notice: 'Status was successfully created.' }
        format.json { render json: @status, status: :created, location: @status }
      else
        format.html { render action: "new" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /statuses/1
  # PUT /statuses/1.json
  def update
    @status = Status.find(params[:id])

    respond_to do |format|
      if @status.update_attributes(params[:status])
        format.html { redirect_to @status, notice: 'Status was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /statuses/1
  # DELETE /statuses/1.json
  def destroy
    @status = Status.find(params[:id])
    @status.destroy

    respond_to do |format|
      format.html { redirect_to statuses_url }
      format.json { head :no_content }
    end
  end
end

The index action is called, which creates an instance variable @statuses which is assigned to an array of the whole contents of the database' status table. The @statuses array is comprised entirely of sub-arrays, and each sub-array consists of the tables rows: .e.g:

<Status id: 19, content: "Aright", created_at: "2013-09-03 21:28:26", updated_at: "2013-09-03 21:28:26", user_id: 3>

Assumption. Please clarify. The Status is capitalised, so rails knows this is a data base request, clarified by the methods called to it (in this example, '.all'). Rails looks for a table called statuses, the pluralised noun of Status. Models don't seem to used when reading data from a table.

Do not understand at all. Please explain Next in the index action is a loop:

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

This is actually one of the few aspects of using rails I have literally 0% understanding in, so I'd seriously appreciate some help here. Not a clue.

What is format? It appears to be a hash of lamdas and functions that make no sense at all. Why does it have to be in a loop? And how does calling the .html and .json methods on it alter the view?

Anyway, now that the index action has been called, rails automatically serves the view inside the statuses directory that's named 'index'. Here is that view:

<h3> Listing all statuses </h3>
<%= link_to "Post a new Status", new_status_path, method: :get, class: "btn btn-success"%>

<% @statuses.each do |status| %>
    <div class="status">
      <strong><%= status.user.full_name %></strong>
      <p><%= status.content %></p>
      <div class="meta"> 
        <%= link_to time_ago_in_words(status.created_at) + " ago", status, data: {confirm: "Ready to see the status?"} %> | 
        <span class="admin">
          <%= link_to "Edit", edit_status_path(status) %> | 
          <%= link_to "Delete", status, method: :delete, data: {confirm: "Are you sure you want to delete this status?"} %>
        </span>
      </div>
    </div>
 <% end %>

Assumption. Please clarify. Rails automatically allows instance variables to be shared between controller actions and their respective views. In this example, instance variables are shared like this: statuses_controller.rb => index.html.erb

The first erb tag we come across is that which creates a 'post new status' button:

<%= link_to "Post a new Status", new_status_path, method: :get, class: "btn btn-success"%>

Assumption. Please clarify. link_to is just a method that turns its first argument ("Post a new Staus") into the html value of the button. Its second argument, (new_status_path) forms the link. It can either be a hard-coded string or the result of a method. Its third argument defines the http verb that will passed into the browsers request. (method: :get) I assume you can also pass in arguments such as method: :post and method: :delete. Why they are symbols I don't know. Also, why are symbols so prevalent in rails, they seem like an annoying way to set parameters? The final argument (class: "btn btn-success") simply sets the button's css class.

Assumption, please clarify

Before we move on, I'd like to discuss the concept of the new_status_path method. My understanding is that they're dynamically created methods that resolve to the route set in your routes directory.

This is my understanding. Here is a route:

get 'register', to: 'devise/registrations#new', as: :register

The first argument ('register') is a string that matches the http request verb. I assume it can be changed to 'post' and 'get' and others things. The second argument ('devise/registrations#new') is ** a little trickier for me to understand **. It appears to simultaneously both match the url with the location it should go to. A url devise/registrations#new does indeed match to the registrations controller's new action, and the new view. The only way you can tidy up the urls is the third argument: (as: :register)

By creating this symbol, you can now reference this route anywhere in your app simply by writing this method register_path By exension, then, would this work?

as: :foobar would be referenced by the following method foobar_path

If I'm right, how then, does new_status_path resolve to the status controller's new action? No where at all in the routes file is this included, as I'd expect:

get 'post', to: 'status#new', as: :new_status

However, there is this:

resources :statuses

I assume this is a rails shorthand for something, but what? How do all routes concerning statuses work flawlessly? Could literally be magic. Someone please explain. These are (I would have thought) specialised controllers and actions, with actions such as new and edit. How does resources :statuses handle all of this?

Now we have a loop that goes through each hash in the @statuses array, in effect putting each database row in a variable called status.

<%= status.content %>

This is an easy one. It resolves to the contents of the hash who's key is content: . However, here's what I assuming and I'd like someone to clarify: the methods you can call are dynamic, and are created by rails based on the hash' keys. For example:

status.inspect #=> <Status id: 19, content: "Aright">
status.test #=> ERROR NO METHOD

status.inspect #=> <Status id: 19, content: "Aright", test: "I'm called by a dynamically created method">
status.test #=> "I'm called by a dynamically created method"

status.user.full_name

This is a bit harder, so I'd like a lot of explaining here! I know exactly what it does, but how does it work? In the status model, we set

belongs_to :user

which establishes a relationship between the status and user tables, a relationship I'm still a bit vague about.

When we call status.user.full_name, rails somehow knows to pull up the user table, and look at the row with the same user_id of the id of status hash currently in the loop. From there, calling full_name on it simply resolves to the contents of the full_name column, so that's easy enough. But I still feel a bit shaky about that works exactly. In order for this to work you need to remember the following things:

a. An id column on the table that belongs_to (in this case the users table) b. An id column preceded by the name of the table it has_many of. (in this case, 'user_id' column in the status table) c. A relevant belongs_to method in the belong_to table's model. (in this case the status model needs to contain belongs_to :user) d. A relevant has_many method in the has_many table model. (in this case the usr model needs to contain has_many :statuses

Is this understanding correct??

Now we have three link_to methods which I'll briefly discuss, as I understand these

 <%= link_to time_ago_in_words(status.created_at) + " ago", status, data: {confirm: "Ready to see the status?"} %> |         
<%= link_to "Edit", edit_status_path(status) %> | 
<%= link_to "Delete", status, method: :delete, data: {confirm: "Are you sure you want to delete this status?"} %>

time_ago_in_words simply turns the status array's created_at value into a human readable format. eg..

created_at: "2013-09-04 00:30:13" => About four hours ago. 

The method: is just setting the http verb for the routes to make sense of it.

When you pass in the data: key into the link_to method, does it automatically create alerts on click? Why this mad syntax: {confirm: "Are you sure you want to delete this status?"} ?

Setting the "confirm:" hash sets the string that will be passed into the alert message.

Phew! That's pretty much all the grey areas in my understanding so far, so I'd love it for someone to explain these! I actually 100% understand the concepts, just a bit shaky on some of the finer points. I don't want to learn what's going on inside rails just yet, just how best to utilise it.

1 Answer

Wow, Julian, that's an intense post! Mind splitting this up into several questions rather than one big post, and then maybe link to them from here, so that I can help you out one by one and make sure that others can find what they're looking for when they have similar questions?