Stringify Time Gem

This gem was created following the Rails plugin made in Railscast 033 Making a Plugin.

Installation

Add this line to your application’s Gemfile:

gem 'stringify_time'                                                   

And then execute:

$ bundle                                                               

Or install it yourself as:

$ gem install stringify_time                                           

Usage

Within an the model add stringify_time passing in a symbol that you want to set as the attribute you want aliased as a virtual attribute string.

class Task < ActiveRecord::Base
    stringify_time :due_at
end

This will create the due_at_string getter and setter methods within the Task model. You can then access this attribute in the views like so:

_form.html.erb

<%= form_for @task do |f| %>
  ...
  <div class="field">
    <%= f.label :due_at %><br>
    <%= f.text_field :due_at_string %>
  </div>
  ...
<% end %>

Your users are now able to type in the date into a text field instead of using the Rails’ default datetime_select dropdowns.

Railscast – 028 In Groups Of

The GitHub Repo
The Heroku App

Faster

I’m noticing I am getting faster. I’m attributing this to making essentially the same application numerous times with this study method. What I am learning that was stored in short-term memory, is slowly moving into the long-term memory part of brain. I also thinking about creating a bash script to help with creating a new GitHub repo for each new project.

In Groups Of

Using the in_groups_of method was fairly straight-forward. Create an instance variable of an array of object records, then call in_groups_of on it within the view. The first argument is how many objects are within one group, and the second argument is the object to pass in for padding. Padding meaning if you had 6 records with in_groups_of(5, false), the it would create the array [[1,2,3,4,5],[6,false,false,false,false]]. You can use this newly generated 2d array in a loop like so.

<table>
  <%= @tasks.in_groups_of(3, false) do |row_tasks| %>
    <tr>
      <% row_tasks.each do |task| %>
        <td><%= task.name %></td>
      <% end %>
    </tr>
  <% end %>
</table>

The first loop is to create an array called row_tasks. You then iterate through that row_tasks array to get at each individual task record.

Railscast 023 Counter Cache Column

The GitHub Repo
The Heroku App

Rails 4.1.0rc1

This episode I wanted to try out the new 4.1.0rc1 version of rails. I had a weird issue when I tried to enter the rails console when I had pg install and marked into the production group like so

gem 'sqlite3', group: :development
gem 'pg', group: :production

I entered rails c and got

Could not find pg-0.17.1 in any of the sources
Run `bundle install` to install missing gems.

Even after I ran bundle install and the output says I have it installed, I was unable to enter the console. I temporarily commented it out in order to work on the actual project. After I was finished with the project, I went to prepare the project to be hosted on Heroku. I uncommented the pg line, then tried bundle install again. This time I was able to enter rails console without any projects. I was in another tab this time. I’m not completely sure why this happened, but my best guess is that bash or rvm didn’t load completely in the tab I was attempting to run rails c on. Embarrassingly enough, I actually opened an issue on GitHub on the Rails repo.

Create records with seed.rb

I populated the database using the seed.rb. Instead of declaring each record one by one, I did it dynamically with ruby. More in the blog post.

Counter Cache

The concept this episode was adding a counter cache column to the the projects table. This allows us to call project.tasks_count instead of project.tasks.count. The latter is inefficient because the database not only returns the projects, but also all the tasks associated with that task. The former improves performance by allowing us to only send the projects’ object which contains the tasks_count attribute.

The Migration

The migration wasn’t too different from what I’ve seen before, but there were a few things to take note of.

class AddTasksCount < ActiveRecord::Migration
  def self.up
    add_column :projects, :tasks_count, :integer, default: 0

    Project.reset_column_information
    Project.all.each do |p|
      Project.update p.id, tasks_count: p.tasks.length
    end
  end

  def self.down
    remove_column :projects, :tasks_count
  end
end

There is a default value on the tasks_count column. This default value allows us to increment and decrement when new tasks are added or deleted for each given project.

reset_column_information

According to the Ruby on Rails API the reset_column_information method resets the cached information about a column. This is useful because if you didn’t run reset_column_information, then the update of the tasks_count could be incorrect.

Update()

The update() accepts two arguments an id and an attribute. The attribute could be a hash. So p.id designates the correct project while tasks_count: p.tasks.length updates the tasks_count column with the correct value.

Counter Cache: true

Finally you add counter_cache: true in the task.rb

class Task < ActiveRecord::Base 
  belongs_to :project, counter_cache: true 
end

Now counter caching is enabled.

Further reading on the Rails Guides

Railscast 022 Eager Loading and Joins

The GitHub Repo

The Heroku App

Setup

Although it might not be necessary to rebuild the starting app at the start of each episode, I find it useful. I just saw that the each episode’s repo has a before and after app. While I may use this in the future, I want to have muscle memory in creating a basic app up and running. I also just noticed that the before app included seeds.rb to populate the database. I may not want to copy the whole app, I am not above saving myself time tediously creating custom records.

ProductsController

The whole episode put a large focus on the ProductsController. The original index action created the @products instance variable by:

@products = Product.order('name')

getting all the product records and ordering them by area. The problem Eager Loading tries to solve is the following request made in the view.

<%= product.category.name %>

This is commonly known as the O(n + 1) problem. Where the query to get the the product is accompanied by another query to get the product’s category name. I’ve been interviewed about Big O Notation before, so I believe that its a topic worthy of its own post.

Joins

The way I learned about both Inner Join and Outer join was watching schneem’s video about ActiveRecord Joins as part of his open Ruby on Rails course videos. So when we call

`Product.order('category.name').join(:categories)

what is happening is that ActiveRecord is creating a virtual Products_Categories table. Because Product is the model which the methods are being called on, then an array of products are returned. The virtual table joins the product’s category_id with the corresponding category with the matching id. It would look something like this

+-----------------------------------------------+
| Products_Categories (virtual) Table           |
+----------------------------------+------------+
|Products                          | Categories |
+----+------+-------+--------------+----+-------+
| ID | Name | Price | Category_id  | ID | Name  |
+----+------+-------+--------------+----+-------+
| 12 |  Toy | 12.43 |      2       |  2 | Toys  |
+----+------+-------+--------------+----+-------+

This is an inner join. The inner join is includes all the records that has a matching category_id. If we created an outer join like this:

'Product.join('LEFT OUTER JOIN categories on products.category_id = categories.id')`

We could select all the records even those that did not have the three requirements needed to be included in an inner join.

  1. Product must have a category_id,
  2. Category must have a ID, and
  3. they must match.

In the case where a product does not have any categories and you wanted to find all those records, you would use a Outer Join. The join method above accepts custom SQL commands. So the SQL command above includes any matches that have the corresponding id and category_id and those that do not. It then takes the products from the left side of the column. To find records where there are no categories associated, you would write the following:

'Product.join('LEFT OUTER JOIN categories on products.category_id = categories.id').where('products: { category_id: nil }')`

The thing I’ve messed up on has been the pluralization of the table names while writing a custom SQL command. I have had times where I left out the s in products and used the singular category instead of the plural categories. The way I need to remember this is by remembering that the tables holds multiple records, thus the table names are always plural.

Select

To continue on with the episode’s lesson, select as used to select what records were to be queried from the database from the ProductsController

    @products = Product.order('categories.name').joins(:category).select('products.*, categories.name as category_name')

The select method used here has two arguments being passed in to limit the data returned. The first products.* is a SQL command to return all the products from the database. The second categories.name as category_name returns only the categories’ name. The as category_name aliases the data dynamically within the select method, so the attribute can be referenced from the model.

In the views you can replace product.category.name to product.category_name. In order to be sure that the category_name attribute is always available you have to create a custom getter method within the product model. This way you are not relying on the select method solely.

class Product < ActiveRecord::Base
  belongs_to :category
  def category_name
    read_attribute('category_name') || category.name
  end
end

The database is first checked if there is a category_name alias in the database. If there isn’t an aliased category_name, then it fetches the name through the ActiveRecord association.

Railscast: 017-habtm-checkboxes

The GitHub Repo The Heroku App

Setup
The setup for this episode because it had a has_many :through association. This is useful to find a record from an instance of the first model via a third model. The way this association was done in this episode was by creating three models, product, category, and categorization. These are the relevant lines of code:

class Product < ActiveRecord::Base
  has_many :categorizations
  has_many :categories, through: :categorization
end

class Category < ActiveRecord::Base
  has_many :categorizations
  has_many :products, through: categorization
end

class Categorization < ActiveRecord::Base
  belongs_to :product
  belongs_to :category
end

Just like when you have a has_many and belongs_to relationship, you must define the foreign key within the table that has the belongs_to method. In this case it is the Categorization model. The schema would look like this.

create_table "categorizations", force: true do |t|
  t.integer 'category_id'
  t.integer 'product_id'
  t.datetime 'created_at'
  t.datetime 'updated_at'
end

This setup allows us to call @product.categories. @product.categories returns an array of category objects associated through the categorization table. This is similar to how you would create followers and followed_users for a user.

Form
The main part of the episode was about how you can create checkboxes to select the categories. First obvious things to do are to loop through all the categories and display them in the _form partial. The tricky part comes with choosing a check_box or a check_box_tag. You want to choose a check_box_tag so you can display each category, not just one.

Next you want to fill in the value of checked or not checked. The second argument passed into the check_box_tag is the category.id. The third is the value of checked or not checked. The way you designate the value is by passing in true or false. The way it is done in the episode is by finding the @product.category_ids and checking if the category.id from the block is included within the @product‘s category_ids.

Now if you refreshed the page, the value is correctly displayed. A hidden_field_tag is also created in order to make sure that the form is submitted with a default value of nil. The reason you want to include this nil category_id field is to make sure that if no checkboxes are checked, then an empty array is passed as a parameter.

Ryan adds a usability enhancement by allowing users to click on the text to check and uncheck boxes. He first creates a unique id for each checkbox with dom_id. Next he adds a label_tag to the text. Oddly enough the dom_id method has no description within the Ruby on Rails API. It just has the source code. dom_id seems to be creating a unique string from the object’s model and id values. In the categories example, the id was defined as category_1 and so on.

The pertinent code:

<%= hidden_field_tag "product[category_ids][]", nil %>
<% Category.all.each do |category| %>
  <%= check_box_tag "product[category_ids][]", category.id, @product.category_ids.include?(category.id), id: dom_id(category) %>
  <%= label_tag dom_id(category), category.name %><br>
<% end %> 

Gotcha
One gotcha you have to watch out for when following this episode and creating a Rails 4 app is Strong Parameters. I was able to find a post on CoderWall that almost translated one-to-one to what I needed to do. You have to define the category_id param as an array. The product_params method definition in ProductsController:

def product_params
  params[:product].permit(:name, :price, category_id: [])
end

Railscast – 002 Dynamic find_by Method

The GitHub Repo

I was arguing if this episode was even worth creating a project for. Decided to create since it would be so quick to make.

The episode talks about how you can replace:

class TaskController < ApplicationController
  def incomplete
    @tasks = Task.find(:all, :conditions => ['complete = ?', false])
  end

  def last_incomplete 
    @task = Task.find(:first, :conditions => ['complete =?', false], :order => 'created_at DESC')
  end
end

With:

class TaskController < ApplicationController
  def incomplete
    @tasks = Task.find_all_by_complete(false)
  end

  def last_incomplete
    @task = Task.find_by_complete(false, :order => 'created_at DESC')
  end
end

Attention should be drawn to the find_all_by_complete method used. This is a shortcut for the first find methods with all of the options passed in. The word that follows the by is the column that is in the Tasks table. You can then pass in the value of the records for that column you want returned. If you want only a single record that matched the conditions, then you would omit the all from find_all_by_complete making it find_by_complete. If you were finding a record by its name, then you doing this:

Task.find_by_name('bob')

Railscast – 016-Virtual-Attributes

The GitHub Repo
The Heroku app

I found this episode useful. It showed me that a model’s attribute does not have to be directly on one of the table’s columns. Not only did I learn about virtual attributes, but I also improved on associations, validations, and callbacks.

The virtual attributes were easy enough to understand. You create a setter and getter method named with the desired virtual attribute name. In the episode’s case it was price_in_cents sort of aliased to price_in_dollars. Within the method you could change the value of the virtual attribute to match whatever is in the database.

def price_in_dollars
  price_in_cents.to_d / 100 if price_in_cents
end

def price_in_dollars=(dollars)
  self.price_in_cents = dollars.to_d * 100 if dollars.present?
end 

Strftime

This is the first time I used the :strftime method, but it is not too dissimilar to how I have formatted dates within the terminal.

Rails 3 to Rails 4

One thing to note, these videos date back sometime before the current Ruby on Rails 4.0 release, thus I must convert some of the techniques shown in the videos into whatever they translate to in the new version of the framework. An example of this is the use of attr_accessible. Attr_accessible has been incorporated in the the strong parameters update in Rails 4. So instead of

attr_accessible :name, :price_in_dollars, :released_at_text, :category_id, :new_category, :tag_names

You would do the following in the ProductsController

def product_params
  params.require(:product).permit(:name, :price_in_dollars, :released_at_text, :category_id, :new_category, :tag_names)
end

Associations

I knew I was a little weak with associations, so when I saw that this project had categories, products, tags, and taggings, I decided to make everything from scratch. I followed along with the schema to create the migrations needed. When creating a has_many and belongs_to relationship you always put the parent id onto the child’s table. Example:

class Product < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  has_many :products
end

The schema would look like this:

 create_table "categories", :force => true do |t|
    t.string   "name"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "products", :force => true do |t|
    t.string   "name"
    t.integer  "category_id"
    t.datetime "created_at",     :null => false
    t.datetime "updated_at",     :null => false
  end

This relationship is similar to the taggings, tags, and products relationship. The taggings has the foreign key for both the tags and products. The difference is that products has_many tags through the taggings model.

Validations

I liked how Ryan Bates created his own custom validation method with check_released_at_text The validation first check if the released_at_text instance variable is present and the time is nil. If it is, then add to the errors object with a custom error message. If there was an ArgumentError, then again the errors object is appended with the custom error message. Creating a custom validation adds more control than if some of the more generic validation methods like presence or length.

Callbacks

The callbacks created this episode used before_save. The reasoning for this is to actually save the instance variable’s values to the database in the correctly formatted form. In the create_category callback it actually creates a new category record.

  def create_category
    self.category = Category.create!(name: new_category) if new_category.present?
  end

Pluck

The first time I’ve seen the pluck method used. I looked it up and found that tags.pluck(:name) is a shortcut for tags.map(&:name). The goal is to get only a certain attribute from the model.

Those where the noteworthy parts of the episode.

Make all Railscast Projects

I came across a post about someone asking what was the best way to learn Ruby on Rails via Quora. One answer suggested one of the best ways was to follow along with every Railscast project then upload the repo to both GitHub and Heroku. I liked the concept, so I have bought a membership of Railscast and have downloaded all the episodes.

While the goal is to create every project, I will watch every episode and decide if it would be useful to make the project or not. Some episodes are just small tips, so creating a new project just to use that one tip seems inefficient.

I might be repeating what episodes showed, but I found that writing about what I learnt from the episode solidifies what I have learnt. Similar to language learning, you need a balance of input and output to get good at any skill. The input here are the Railscast episodes and the things I look up to finish the apps, and the output are the working app and the blog post.

The first few days of trying this method, I created an app then wrote up the blog post. This takes a lot of context switching between tasks. I am currently trying to go through as many Railscasts in one day, then writing about each the following day.