| « Sharing controllers and views with polymorphic resources | Scramble email addresses in views to reduce spam » |
During the development of some web applications in the past, I found myself using various techniques again and again on different projects. Here's a collection of five things that I discovered over the time and that I found most useful.
Follow up:
The rails console is an incredible helper during development. You can work with models, manually test things or just make changes to your data. Even in production mode, it comes in handy to use the console to manually change data on a live system if absolutely required.
However, the standard console feels like a dumb terminal; it has almost no input assistance like we know from e.g. the bash shell. But luckily, there's Wirble, a gem that pimps your irb console.
Simply install the wirble gem
Code:
# sudo gem install wirble |
and put the following into ~/.irbrc
Code:
require 'rubygems' | |
require 'wirble' | |
Wirble.init | |
Wirble.colorize |
and your console feels much more comfortable. You get
Additionally I usually redirect the Rails debug log to the console while developing, so that I can see what database queries are done when using methods on models. Simply drop the following into ~/.irbrc and the Rails logging will be printed to the console:
Code:
require 'logger' | |
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER') | |
Object.const_set('RAILS_DEFAULT_LOGGER', Logger.new(STDOUT)) | |
end |
It's good practice to annotate your code with a comment at places where you know that further work must be done. Usually these annotations are placed as a comment into the source. Over time some keywords have been well-established for this purpose. Namely there are:
Usually, if you use an editor with syntax coloring, comments containing these keywords will be extra highlighted in some way to get your attention.
Additionally, Rails has some rake tasks that search for comments with the above keywords and print lists of all occurrences, including the filename, line number and description (remaining text after keyword) of such an annotation.
rake notes:todo - list all TODO commentsrake notes:fixme - list all FIXME commentsrake notes:optimize - list all OPTIMIZE commentsrake notes - list all of the above commentsActiveRecord does not support attribute of type ENUM or SET natively. An easy way to come around this limitation is to use an integer or a string instead. I found it most useful to use a string columns, restrict the values by using validations and additionally symbolize the values so that they look more ruby-style.
Validation is pretty easy and values can be symbolized by defining own getter and setter methods. Lets take a user that can be active or inactive as an example:
Code:
class User < ActiveRecord::Base | |
validates_inclusion_of :status, :in => [:active, :inactive] | |
| |
def status | |
read_attribute(:status).to_sym | |
end | |
| |
def status= (value) | |
write_attribute(:status, value.to_s) | |
end | |
end |
To make this easier for multiple attributes and work with nil values, I published a plugin that provides a symbolize class method. Using the activerecord_symbolize plugin, the above becomes as easy as symbolize :status. More background info on how it works can be found in an older post in my blog.
The activerecord_symbolize github repository doesn't seem to work at the moment, since there's a problem with my github account. I already notified the github team and hope they'll address it soon.
If you put your email address on a public web page, you can usually be sure to get tons of spam from there on, because address harvesters will sooner or later visit your page and recognize the email address.
To prevent spam harvesters from gathering your email addresses, you can try to scramble them so that a harvester won't recognize them but humans can still read them. One way of doing so is included in Rails' view helper mail_to.
mail_to can be used with various options. :replace_at and :replace_dot will obfuscate the email address by replacing the @ character and dots by the given string.
So using :replace_at=>'(at)' and :replace_dot=>'(dot)' would output:
me(at)example(dot)com
Note that only the displayed address is obfuscated, so the plain address is still present in the href attribute of the link. Therefore this method is useless in my opinion, since it only annoys visitors with obfuscated addresses and does not hinder harvesters from gathering the link.
The :encode option can be used to encode the email address using :hex or :javascript. Using :hex will replace all letters of an email address with their hex value, so .com becomes .%63%6f%6d
Using :javascript is probably the best mail_to can do, since it completely replaces the link with a JavaScript snippet that does not look like a link or an email address anymore. So the generated page source doesn't contain any email link, but if displayed in a browser, the JavaScript executes and shows the email address.
However, I suppose that an email address encoded this way can still be harvested easily, since it can be made visible without actually running the JavaScript. So I recently wrote a view helper that creates a more complicated JavaScript snippet (one that cannot easily be reversed without actually executing it).
A method usually returns an object if the operation succeeded - or nil if not. E.g. ActiveRecord finders return nil, if no matching record was found. So the returned value has to be checked for nil before doing further actions on it, or you risk calling a method on a nil object (everybody probably knows the NoMethodError: You have a nil object when you didn't expect it!)
So at many places, code looks like this:
Code:
user = User.find_by_username('foo') | |
user.dosomething unless user.nil? |
There's a smart solution of making this look much nicer. On ozmm, Chris wrote how he defines a method Object#try, that calls a method if it exists and returns nil otherwise. Here's the snippet, slightly modified so that it supports multiple parameters:
Code:
class Object | |
def try (method, *args) | |
send(method, *args) if respond_to?(method) | |
end | |
end |
With this, the method try can be called on every object (including nil values, since nil is also an Object). try calls the method named in the first parameter, if it exists and returns it return value or nil if the method doesn't exist. This way, the above case can be handled much easier and more readable:
Code:
User.find_by_username('foo').try(:dosomething) |
You can even cascade it. Instead of writing:
Code:
user = User.find_by_username('foo') | |
address = user.address unless user.nil? | |
address.dosomething unless address.nil? |
you can now do it this way:
Code:
User.find_by_username('foo').try(:address).try(:dosomething) |
Trackback URL (right click and copy shortcut/link location)