One of the things I really love about Ruby on Rails is that, for every discovery, there seem to be two more waiting on the horizon; better, neater, faster ways of doing things. I, as programmer, am prone to becoming sidetracked by trying out newly discovered methods, and sometimes I lose site of some basic software principles. One of the most basic of these is "separation of concerns" (SoC).
I have found that the extreme accessibility of Rails models allowed me to pick up some bad habits: namely just grabbing models willy-nilly and having my way with them in my controllers. Although Rails implements MVC, it can only do so much to encourage good coding practices, and the rest is up to you. Here are a few lessons I've learned about keeping my controllers clean:
1) Stop playing with your parameters: Formatted user input is extremely common, and there are several approaches to dealing with the validation, character stripping, and reformatting required to support it. I'm ashamed to admit that the last project I worked on "gsubs" were splattered everywhere in the controller actions in order to remove formatting characters. First, assuming that formatting characters were input correctly by the user is bad bad. And this is essentially what's happening when validation occurs after character stripping. For example, say we have a phone number that was typed in as 12345-67890. Now, if we strip the '-' character and validate numericality and length, whoila, we have a valid phone number. WRONG! How do we know if it's supposed to be 123-456-7890 OR 1-234-567-890 and they forgot a digit? The answer is, we don't, so don't assume. There is a world of ready to use regular expressions out there (lately I've been referencing Alexey's Blog). Make use of them in conjunction with ActiveRecord's validates_format_of method.
OK, now we know that we can validate our user's input with formatted characters and all. We know what our user's intentions are, but now we still have to get rid of those pesky formatting characters before storage. Well, we could create a method for the model and call it from the controller (ugh), or, the cleaner approach is to add a method to the model's ActiveRecord callback before_save method: something like "before_save :remove_those_pesky_characters".
The result of implementing the above procedures is we don't have to do any parameter manipulation inside our actions to deal with formatting characters. Data manipulation and validation is handled in the model where it belongs.
The next part in this series I will talk about rolling up model dependencies using the ActiveRecord after_create callback.
Good stuff! Another big win for doing validation in the models is that it makes automated testing so much easier.
ReplyDeleteAbsolutely. Being able to test against validation rules is very important in unit testing.
ReplyDelete