Railscast 053 Handling Exceptions

GitHub Repo

Heroku App

Rack Middleware

I created this episode in order to understand how rack middleware works. There was really only one line that pertained rack middleware

config.exceptions_app = self.routes

This line is a little hack to define the Rails routes as the rack middleware app that should handle exceptions. From the routes we can then match the status error in a route and map to a controller action.

Route

match '(errors)/:status', to: 'errors#show', constraints: {status: /\d{3}/}, via: :get

This route line provided me with a few lessons. the () in a route is an optional route. A route like products/:id(/:type/:year) would match a route for the product from the id and optional add the type or year params if specified.

The constraints part about further specifies what is acceptable in a route and what is not acceptable. Here we are using regex to constrain the status param to only be 3 digits. This could be useful when getting params from the route. The constraints can be analogous to how validations works for models.

Controller

class ErrorsController < ApplicationController
  def show
    @exception = env["action_dispatch.exception"]
    respond_to do |format|
      format.html { render action: request.path[1..-1] }
      format.json { render json: {status: request.path[1..-1], error: @exception.message} }
    end
  end
end

The @exception instance variable is set to the type of exception raised. The exception is store in the environment’s action_dispatch.exception. The action responds to different formats like html or json. Therequest.pathhas[1..-1]to turn/404to404`

Railscast 052 Update through Checkboxes

The GitHub Repo

The Heroku App

This episode combines the technique shown in Episode 017 habtm checkboxes and Episode 35 Custom REST Actions to update a task’s complete attribute through checkboxes.]

Some of the differences in this episode were the methods used to update the complete attribute. In episode 035, the update_attribute() was used to update a single record. In this episode we used the update_all() method. There was a slight difference in how the update_all() method was used in the video and how it is currently used. In the video the update_all() method accepts two arguments, the attribute with updated value, plus the ids of tasks to be updated. The update_all() method has been changed to accept only one argument, the attribute with the updated value. This creates some problems in specifying which record to update. Luckily, the API for update_all showed the correct way to use the updated version of update_all().

Task.where(id: params[:task_ids]).update_all([“complete=?”, true])

We use the where() method to return tasks fitting the passed in conditional.

The params[:task_ids] were sent from the form within the view.

<%= form_tag complete_tasks_path, method: :put do  %>
  <ul>
    <% @incomplete_tasks.each do |task| %>
    <li>
      <%= check_box_tag "task_ids[]", task.id %>
      <%= task.name %>
    </li>
    <% end %>
  </ul>
  <%= submit_tag "Complete task" %>
<% end %>

Here we use the form_tag because the form is not directly editing attributes on a model. We then specify the path and method to put. I am just realizing this now, but this put should be a patch to match up with what the Rails core team has been doing in transitioning from put to patch to match with RFC’s specifications.

The next part to focus on is the <%= check_box_tag "task_ids[]", task.id %> line. We are creating checkboxes for each task with the value of the task’s id. The name for each checkbox can be specified to task_ids[] because we are using a general check_box_tag. task_ids[] allows the task_ids parameter sent from the form to be an array able to hold multiple records. This is where we get the params[:task_ids] array passed into the where() method.

Railscast 046 Catch All Route

The GitHub Repo
The Heroku App

This episode focused on creating a catch all route that redirects to a product’s page based on the partial route typed in. Example: /tele to /television

The routes syntax has been updated since the creation of the episode.

match '*path' => 'your_controller#your_action', via: :get

StackOverflow

You would want to create this catch all route at the bottom of your routes file because it would match all the requests coming into you Rails app otherwise. Because the match all routes redirects to the product page you actually are looking for, this isn’t that bad of an outcome.

After the route catches the input of the user from the route, it then calls the redirect#index. In this controller we can control the behavior of that route.

class RedirectController < ApplicationController
  def index
    if Rails.env.development? || Rails.env.test?
      product = Product.where('name LIKE ?', "#{params[:path].first}%").first
    elsif Rails.env.production?
      product = Product.where('name ILIKE ?', "#{params[:path].first}%").first
    end
    redirect_to product_path(product)
  end
end

In this controller I reused what I learned about PostgreSQL’s LIKE and ILIKE functions from the episode about Simple search forms to separate difference lines of code based on the environment.

There is a single action, index, that is called from the catch all route. We find where the product has a name that is similar to the partial parameter given in the route. We access this partial parameter through the params has with params[:path]. We also call first() to get the first value of the hash. If the user inputed /foo/bar/baz, then it would use the foo value only. Again from episode 037 simple search form, we use the SQL Wildcard % to match anything that starts with the partial route given. If there are multiple records that have the same partial route, then we call first() again at the end of the line to only retrieve the first record.

get '*path' => 'redirect#index'

Railscast 042 With Options

class User < ActiveRecord::Base
  with_options if: :should_validate_password? do |user|
    user.validates_presence_of :password
    user.format_of :password, with: /^[^\s]+$/
  end

  attr_accessor :updating_password

  def should_validate_password?
    updating_password || new_record?
  end
end

class Account < ActiveRecord::Baase
  with_options dependent: :destroy do |acc|
    acc.has_many :customers
    acc.has_many :products
    acc.has_many :invoices
    acc.has_many :expenses
  end
end

This is a convenient method to be aware of. When there are numerous records that have the same options, then using with_options could clean up the code and it more DRY.

The with_options() method accepts the options as the first argument, then it accepts a block for the model class. This argument is the object used to call the validations on. In the case of user, user.validates_presence_of :password does the normal presence validation, but adds the benefit of using the with_options() method.

Further Reading

http://apidock.com/rails/Object/with_options

Railscast 208 ERB Blocks in Rails 3+

GitHub Repo

Heroku App

I was originally going to create the episode 40 blocks in view, but there was a comment mentioning that episode 208 was the updated version. I did watch episode 40 nonetheless, and I noticed how much Rails has improved. The way to create a block in view in Rails 2 was by concatenating and using a block.binding. This seems like a hack compared today’s Rails standard.

For comparison the code for episode 40

def admin_area(&block)
  concat content_tag(:div, capture(&block), :class => 'admin'), block.binding if admin?
end

Episode 208

def admin_area(&block)
  content_tag(:div, :class => "admin", &block) if admin?
end

The line for the episode 208 was shorter because it eliminated concat capture() and block.binding. concat was rendered unnecessary after ERB used the <%= %> tag to signify whether or not the output would be rendered to the view. capture() tried to capture the output of a block’s yield. The content_tag now is able to accept a block as an argument without the need for capture(). block.binding binds to the erb templating. I’m not sure why this became unnecessary, but I suspect the revision of erb fixed this.

Assets Precompile

While pushing to Heroku the CSS I wrote for the admin_area was not being rendered. I eventually found the answer on StackOverflow. I did not have the rails_12factor gem. After further reading of the README for rails_12factor, rails_12factor allows static assets to be retrieved despite using a proxy like Nginx. A proxy like Nginx routes the asset path of assets/rails.png to public/assets/rails.png. Rails 4 is sort of encouraging the use of a CDN to host static assets. The Readme also linked to the ’12factor’ methodology which seems to touch on devops.

Railscast 038 Multibutton Form

The GitHub Repo

The Heroku App

What I love about following the Railscasts and actually implementing the small features is that making these apps are quick, I’m exposed to something I wouldn’t have been otherwise, and they are straightforward. This episode was no different.

preview_button

<%= submit_tag 'Preview', name: 'preview_button' %>

The Preview button is similar to the the submit button, but it differs in it function. The name for the button defaults to commit when using the submit_tag helper. This is good when you need to create a normal submit button to create or update a record, but in the case of a preview button, you do not want to save the record just yet. Instead of having the name='commit we override this default by specifying the name should be equal to preview_button. With the name now equalling preview_button the parameters hash has "preview_button" => "Preview".

Controller

def create
...
  respond_to do |format|
    if params[:preview_button] || !@project.save
      format.html { render action: 'new' }
      format.json { render json: @project.errors, status: :unprocessable_entity }
    else
      format.html { redirect_to @project, notice: 'Project was successfully created.' }
      format.json { render action: 'show', status: :created, location: @project }
    end
  end
end

We can then use the params[:preview_button] within our conditional in the create action. If params[:preview_button] is not nil, then the controller will redirect to the new view while still having the preview_button parameter present in the URL. If there is no params[:preview_button] defined, then we know that the form was submitted through the normal submit button and not the preview button.

Textilize

<% if params[:preview_button] %>
  <div id="preview">
    <h2><%= @project.name %></h2>
    <%= textilize @project.description %>
  </div>
<% end %>

When we are redirected to the new view, the params[:preview_button] is still defined. We can use this in another conditional within our view to display a preview. Here we are previewing the project’s description using the textilize text helper. This was deprecated back in Rails 2, but I found a gem that dropped in to Rails 3+ that adds this back. There has to be a reason that the Rails Core Team deprecated this, so I do not plan to use this again. Instead I might reuse the code I used to render markdown to the view from my Markdown Todo List Rails API App

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.

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.