Skip to content

if current_user, then logic in views

We all know that we’re not supposed to have logic in our views. But then we still do this constantly:


link_to edit_object(@object) if admin?

Who do you think should CONTROL whether the current user should be able to edit the object? One option would be the object itself. Another good option is the controller. You know who is a bad option? THE VIEW

So when we do the above, we fail.

Here is what I’ve been doing instead. Suppose the code above came from an index page. Then I divide that into two pages: authorized_index and unauthorized_index. They will be identical to the original index page, except for when we find code like the above, we now have

authorized_index

link_to edit_object(@object)

And we just remove the link altogether in the unauthorized_index page.

In the controller, we will have:


respond_with(@objects) do |format|
--if admin?
----format.html { render 'authorized_index' }
--else
----format.html { render 'unauthorized_index'}
--end
end

Now the logic is in the controller, where it belongs!

Hey I think you were expecting an array but you got nil. OH NOES

Here’s a common occurrence for me: I’ve got something like
@cats.each { |cat| cat.color }

And then, at some point, there’s a situation where @cats isn’t assigned to anything (or assigned to nil). Ruby freaks out and tells me “Hey buddy, maybe you were expecting an array????” Well, yes I was, but I don’t care – if there are no cats, then don’t tell me their color. Can’t we just move on, Ruby?

So, standardly, what we do is something ugly like this:

if @cats
@cats.each { |cat| cat.color }
end

But wait! There’s a better way! And here it is:

@cats.to_a.each { |cat| cat.color }

If @cats is already an array, no big deal, to_a does nothing. If, however, @cats is nil, then to_a turns it into an empty array, which means Ruby won’t whine at you about trying to treat it like an array. AWESOME

Why not make default controllers in application controller?

You know what’s boring as hell (and, oh, not very DRY)?

Writing the following controller over and over:


class WidgetController < Application Controller
....
__def index
____@widgets = Widget.all
__end

__def show
____@widget = Widget.find_by_id(params[:id])
__end
end

etc. etc.

Most controllers are EXACTLY the same. And wouldn’t it be nice if, when they are exceptional, that’s made very clear? Doesn’t this sound ideal for making some default methods that can be overridden in the children? And we already inherit from applicationcontroller, so why not do it there?

Here is how I took care of it in the create method (the rest are similar):

 

class ApplicationController < ActionController::Base
....
__# This is equivalent to the following code for each controller:
__# def create
__#   hazard = Hazard.new(params[:hazard])
__#     if hazard.save
__#     flash[:notice] = "Hazard was successfully created."
__#   end
__#
__#   @hazard = hazard
__#   respond_with hazard
__# end
__def create
____model = self.controller_name.singularize.capitalize.constantize
____model_name = self.controller_name.singularize
____symbol = model_name.to_sym
____instance = model.new(params[symbol])
____if instance.save
______flash[:notice] = "#{model_name.capitalize} was successfully created."
____end

____instance_variable_set("@#{model_name}", instance)
____respond_with instance
__end
end

I can’t tell if this is actually a good application of DRY, or if it is a little TOO clever. In any case, it works. The best part is that when I make a new REST controller, it works immediately without me writing any code!

Active Record: find vs. find_by_id

It has been common practice for me in the past to write Page.find(4) to find the Page with id of 4. It seemed a useful shorthand.

And it is, assuming that you know the record exists. If it doesn’t, however, you can get errors. You should instead use Page.find_by_id(4), since you don’t get an error, but rather nil (as I would expect). Watch:

ruby-1.9.1-p378 > Page.all
=> []
ruby-1.9.1-p378 > Page.find(1)
ActiveRecord::RecordNotFound: Couldn't find Page with ID=1
from /home/jon/.rvm/gems/ruby-1.9.1-p378/gems/activerecord-2.3.9/lib/active_record/base.rb:1620:in `find_one'
from /home/jon/.rvm/gems/ruby-1.9.1-p378/gems/activerecord-2.3.9/lib/active_record/base.rb:1603:in `find_from_ids'
from /home/jon/.rvm/gems/ruby-1.9.1-p378/gems/activerecord-2.3.9/lib/active_record/base.rb:620:in `find'
from (irb):4
from /home/jon/.rvm/rubies/ruby-1.9.1-p378/bin/irb:17:in `'
ruby-1.9.1-p378 > Page.find_by_id(1)
=> nil

My Rails setup

Most people seem to use vim to do their rails programming, and I’m sure it has its merits, but it’s just too unintuitive for my tastes. Instead, I use the following setup:

OS: Ubuntu
Writing code: NetBeans IDE (with Ruby extensions). It’s particularly useful when refactoring.
Testing: Shoulda and Cucumber within a terminal
Javascript Testing: Selenium IDE as a Firefox extension
Coverage: Rcov/Simplecov
Finding smells: Reek, RailsBestPractices, and (in general) Metrics gems.

How to add a Rails object to the database with a specific id

I struggled for a long time today trying to create a Rails object at a specific ID (parts of the program depend on there being a specific object at that id). I tried using FactoryGirl:

Factory.create(PublicationType, :id => 1, :name => "Articles")

That didn’t work. Neither would doing it more directly:

PublicationType.create(:id => 1, :name => "Articles")

In both cases, the “id” part was ignored and I just got a new object at whatever the next available id was. Presumably there were SOME publication types in the database, just not at 1. So how do you do it?

Here’s how:

pub = PublicationType.new
pub.id = 1
pub.name = "Articles"
pub.save

Then you get what you want: a new object at 1 with the name of “Articles.

This is the article which saved me.

Minimalist Programming

In Test-Drive-Development and Behavior-Driven-Development, one is supposed to write tests/behavior specs first, and then write code that makes those tests pass. Then you refactor to try to pare that code down to its minimal form, so that nothing is repeated and everything is as simple as possible while still making the tests pass.

In its simplist form, the design philosophy here is:
A piece of code should only exist if and only if there is a test which requires that piece of code.

One could satisfy this requirement in two ways:

Code minimalism:
If a test does not exist which depends on a piece of code, eliminate the code.

Test maximalism:
If a test does not exist which depends on a piece of code, write one that does.

Either way, you end up with a system in which each and every piece of code is tested, at least to some extent.

Although these have the same result of satisfying the requirement, they are obviously quite different styles. In practice, of course, we use something like both of them at once.