CoderByte has numerous programming challenges in many languages. Here I will post and discuss solving and thinking about the solutions.
March 2014
Reach out to at least 10 people a day
I was inspired by a blog post by Michael Thomas about dropping out of college and his experiences. We are of similar age, so we share many of the same thoughts. He talks about real world learning, startups, and the subject of this blog post, network. I quote:
When I was running SkyRocket my goal was to reach out to (email, phone or voicemail) at least 10 people every day. So over the course of the last 9 months I’ve “touched” over 2,700 people and probably met about 500-750 of those people. Some of these people are CEOs of top companies like HootSuite and Mobify, which has its obvious perks, and others are thought leaders who I get to learn from.
Railscast 053 Handling Exceptions
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. The
request.pathhas
[1..-1]to turn
/404to
404`
Railscast 052 Update through Checkboxes
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.
Which has_many association to use?
Has and Belongs to Many Example Repo
Railscast 047 Two Many-to-Many prompted me to ask this. He showed an has_many_and_belongs_to
and an has_many :through
example. From what the episode, Ryan Bates seems to generally like has_many :through
better because it adds flexibility. What are some of the reasons behind this conclusion?
Differences
The Rails Guides on Associations has a section about this.
For has_and_belongs_to_many
the relationship is built through a join table using only two models. A has_many :through
relationship creates a third model that belongs_to
the two models in the relationship. The circumstances you would want a has_many :through
association would be:
if you need validations, callbacks, or extra attributes on the join model.
A case where you might want to have a has_many :through
associations would be if you have a feature of ‘following’ within the app. Each user has followers and following users. One relationship could be established, but both do not necessarily have to be established. In the case of followers and following users, you would actually need two relationship tables in the database. ActiveRecord provides the ability to ‘reverse’ a relationship based on what the foreign key is.
There could be a relationships table with follower_id
and followed_id
. To find a user’s followed users, then you would set the foreign key to the follower_id
. To find a user’s followers, then you would set the foreign key to the followed_id
and rename this relationship to something like reverse_relationship
within the model.
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
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
Railscast 041 Conditional Validations
I ask myself when would I need to use a conditional validation. I could bypass certain validations based on a specific attribute being filled or not.
A big topic of late has been female founders not applying to accelerators/incubators like YC.
Railscast 208 ERB Blocks in Rails 3+
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
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