Railscast 037 Simple Search Form

The GitHub Repo

The Heroku App

Form

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

The form for the search form has many lessons to learn. The use of form_tag over form_for is preferred we are not updating attributes associated with a specific model. Here the form_tag submits to the projects path. Normally when you submit a form using the form_for or form_tag Rails helper Rails create the html tags with a post method filled in. When you submit a post request to the projects path, Rails thinks you are trying to create a new record because of the RESTful design. To counteract this you have to explicitly specify the method used on this form, in this case get.

Controller

def index
  @projects = Project.search(params[:search])
end

Instead of the usual Project.all, we use a search method that we defined in the project model. The search method accepts a argument that is matched with records in the database.

Model

class Project < ActiveRecord::Base
  def self.search(search)
    if search
      if Rails.env.development?
        where("name LIKE ?", "%#{search}%")
      elsif Rails.env.production?
        where("name ILIKE ?", "%#{search}%")
      end
    else
      all
    end
  end
end

This is where most of the work is being done. Here we are defining a class method called search which accepts one parameter. If this parameter is true, then it will search for a name similar to the search argument. There is a conditional based on the environment because the LIKE function in SQLite3 used in development is case insensitive, while the LIKE function in PostgreSQL used in Production is case sensitive. PostgreSQL LIKE To counteract this, I have included the ILIKE function for only the production environment.

The "%#{search}%" confused me, so I asked on StackOverflow about what the % was. Apparently it is SQL Wildcards used to match characters in a string. It is similar to how Regex pattern matches, but SQL Wildcards are much simpler. It appears there are only four syntaxes that can be used. %, _, [], [^]. The % substitute zero or more characters. _ substitutes a single character. [] matches sets or ranges of characters. Example: [abc]% matches anything that starts with abc. Similar to regex you use ^ to declared not. [abc]% matches anything that does NOT start with abc. Similar to Regex, so this was not too mind blowing. The tricky part was learning the syntax used.

Emacs Ruby on Rails Mode: Rinari

I have been developing with Ruby on Rails and Emacs for a good three months now, but I haven’t been using the emacs editor to its full potential. Nothing illustrates that more than not using a Ruby on Rails minor mode like Rinari. I just enabled rinari-minor-mode today and watched the introduction Rinari Screencast, and I’m blown away at how much time I could be saving using come of the commands shown.

You could switch over to the controllers, models and views using the c-c ; f c, m, or v command keys. What I was really looking for was to make the erb <%= %> tags, and the rinari minor mode can do that as well with c-c ' e.

Cheatsheet

 C-c ; f c  rinari-find-controller
 C-c ; f e  rinari-find-environment
 C-c ; f f  rinari-find-file-in-project
 C-c ; f h  rinari-find-helper
 C-c ; f i  rinari-find-migration
 C-c ; f j  rinari-find-javascript
 C-c ; f l  rinari-find-plugin
 C-c ; f m  rinari-find-model
 C-c ; f n  rinari-find-configuration
 C-c ; f o  rinari-find-log
 C-c ; f p  rinari-find-public
 C-c ; f s  rinari-find-script
 C-c ; f t  rinari-find-test
 C-c ; f v  rinari-find-view
 C-c ; f w  rinari-find-worker
 C-c ; f x  rinari-find-fixture
 C-c ; f y  rinari-find-stylesheet
C-c ; s    rinari-script              
C-c ; e    rinari-insert-erb-skeleton 
C-c ; r    rinari-rake                
C-c ; w    rinari-web-server          
C-c ; x    rinari-extract-partial     
C-c ; ;    rinari-find-by-context     
C-c ; d    rinari-cap
C-c ; q    rinari-sql
C-c ; t    rinari-test
C-c ; c    rinari-console
C-c ; g    rinari-rgrep
C-c ; p    rinari-goto-partial
C-c ; '    rinari-find-by-context

more bindings can be seen with c-h b. I just learnt about this command through the Rinari video. It is useful because you can see all the commands associated to different minor modes.

Railscast 035 Custom REST Actions

The GitHub Repo

The Heroku App

This is one of those episodes I needed to see. I haven’t had to use the collection or member blocks in the routes file before, but I’m glad to know what they mean now. member and collection allows the developer to create custom RESTful routes that extends the rails conventions. A member route appends after the /:model/:id, so the controller action has the params[:id]. A collection route appends after the /:model route.

Examples of these two were the routes created in this episode.

resources :tasks do
  get 'completed', on: :collection
  put 'complete', on: :member
end

This creates the normal RESTful Rails routes, but it also create two custom routes. /tasks/completed/ and /tasks/:id/complete. The Rails Guides for Routing was useful for further reading.

TasksController

def completed
  @tasks = Task.where(completed: true)
end

def complete
  @task.update_attribute :completed, true
  flash[:notice] = 'Task Completed'
  redirect_to completed_tasks_path
end

The two custom actions were completed and complete The completed action returns a tasks instance variable where completed is true. The complete action updates an attribute to true, then redirects to the completed tasks view with a flash notice.

To complete a task, the episode shows creating a link with the put method being sent the complete_task_path while sending the task’s id.

Heroku Issue

For some reason when I tried to click on this ‘complete task’ link, heroku is giving me a ‘page doesn’t exist’ error. Locally the link works however. I have opened a StackOverflow question about the issue. I don’t think you need a view for that action because it redirects to the completed_tasks_path. Even the rake routes show a PUT for /tasks/:id/complete. I did discover that the Rails core team has been switching over to the Patch verb over the put http verb. This adheres to RFC specification for partial updates. Even though I tried to change out put for patch, I was unable to get this link working.

Railscast 032 Time in Text Field

Project GitHub Repo

StringifyTime Gem GitHub Repo

The Heroku App

This episode was essentially repeated in Railscast 016 Virtual Attributes. Despite it being a repeat, I decided to create a project for this Railscast because the following episode, 033, used it to make a Rails Plugin. Rather than make the plugin, I wanted to try creating my second RubyGem based on this plugin.

Although I was not aware of this while making the gem, there was another person who had the same idea. His gem is called jakewendt-stringify_time, but it hasn’t been updated four years. The gem I created integrates with the changes made to the Ruby on Rails framework since that gem’s creation.

Because this would be my second gem I have created, I thought I could just model this gem similarly to my first gem body_id. I created the basic gem files using bundle gem stringify_time command. Then I edited the .gemspec file to put in the basic information needed. The part I got confused about was at the part I was going to use railtie. The Railscast simply extended ActiveRecord using the module created in the plugin. Instead of following my previous gem, I decided to try how it was made in the video. I copied the StingifyTime module from the episode and extended ActiveRecord just like it was shown in the episode. I ran rake release and had version 0.0.1 on RubyGems.org. That’s when I created the previous project from Episode 032 to try the gem out. The bad part was, it didn’t work.

After some searching around I noticed other gems did not use extend method on ActiveRecord directly, but they used the .send :include, StringifyTime method to call the include method on a module. So I tried to exchange

ActiveRecord::Base.extend StringifyTime

with

ActiveRecord::Base.send :include, StringifyTime

The problem was I blindly tried to copy and try this method without fully understanding why I was using include instead of extend. Include is used on an instance of a class to add methods, while extend is used to add methods to the class itself. At the same time, I searched my gem on RubyGems.org and discovered the Jake Wendt’s gem based on the same episode. I looked at his GitHub Repo and saw he had an init.rb and rails/init.rb. “Could this solve it?”, I thought. I applied the changes, and the stringify_time method was being include in my rails app.

Metaprogramming

What is so interesting about creating this stringify_time method is that you are writing a program in order to have it write another program. That’s the concept of metaprogramming at least. You could have defined each getter and setter method manually, but that isn’t practical when you have numerous attributes you need to do the same thing on. I have used metaprogramming when I made a seed.rb file to fill up the database with records. These methods saves a lot of time if made correctly.

Unresolved

When I went to edit the date on the form, the date was not updating. This is still a problem I need to solve, and I have opened a question on StackOverflow to try to resolve this issue. While I wait for an answer I’ll keep moving to another Railscast.

Update

Someone on StackOverflow suggested I try using the generated method via the Rails console. I tried to use the rails console, and the due_at attribute was updated. I thought why was I able to update the attribute in the console, but not via the form. The answer was because I was not whitelisting the :due_at_string param in the task_params definition. This is to protect from mass assignment. So the data from the form was never reaching the model because it was being prevented by the controller. A silly mistake to overlook.

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.

Use `gits` instead of `git status`

After using git version control for sometime, you may notice yourself running git status multiple times right before you commit. Like the programmers we are, we are inherently lazy. in a good way. Instead of typing git status numerous times a day, type gits.

Here’s line you’ll need to alias it in the bash terminal

alias gits='git status'

Add this line to either you ~/.bashrc or ~/.bash_profile. Remember to reload bash again by opening a new terminal window so bash can import this alias.

Bonus

alias gita='git add'

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.

Heroku Could not find * in any of the sources

When I was uploading 023-counter-cache-column, I ran into the following error

-----> Ruby app detected
-----> Compiling Ruby/Rails
-----> Using Ruby version: ruby-2.0.0
-----> Installing dependencies using 1.5.2
       New app detected loading default bundler cache
       Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
       Fetching gem metadata from https://rubygems.org/..........
       Fetching additional metadata from https://rubygems.org/..
       Could not find sprockets-2.11.1 in any of the sources
       Bundler Output: Fetching gem metadata from https://rubygems.org/..........
       Fetching additional metadata from https://rubygems.org/..
       Could not find sprockets-2.11.1 in any of the sources
 !
 !     Failed to install gems via Bundler.
 !

 !     Push rejected, failed to compile Ruby app

The issue was with my Gemfile.lock. I needed to run bundle update to make sure this file was updated. After I ran bundle update sprockets changed to version 2.11.0. This makes the error understandable because 2.11.1 would be unavailable through rubygems.org unless specified.

Referenced StackOverflow

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