When to use a bang (exclamation point) after Rails methods
-
Update:
A bang can used in the below ways, in order of my personal preference.
1) An active record method raises an error if the method does not do what it says it will. (e.g. create!)
2) An active record method saves the record or a method saves an object (e.g. strip!)
3) A method does something “extra”, like posts to someplace, or does some action.
4) other things
The point is: only use a bang when you’ve really thought about whether it’s necessary, to save other developers the annoyance of having to check why you are using a bang.
-
When writing methods for active record models, bangs should only come when a) something is being changed in the database or b) calling the method will raise an error if the record is not valid, or if no records are returned (e.g. find! / create!)
When to use a bang:
1 2 3 4 5 6 7 |
# obviously we would write this better in prod, but the point is to show the point class AModel < ActiveRecord::Base def hit! hits += 1 save end end |
When not to use a bang:
1 2 3 |
def modify_something self.hits += 1 end |
In the first method, we are saving the object, in the second we will have to save it if we want the change to actually happen in the db.
The bang provides two cues to other developers.
1) that it’s not necessary to save the object after calling the method.
2) when you call the method, the db is going to be changed.
If bangs are used in other situations, the going gets rough, because it’s unclear what is being saved in what context.
Obviously, this is more a design decision than a hard rule, but I’ve found that it works well for me.
February 11, 2009

I also use the bang when the method is doing something "extra" - which is a pretty loose thing. For example, with Machinist, you might do this:
February 11, 2009 at 6:46 PMdef login!(options = {})
user = User.make(options)
login_as(user)
user
end
That allows this kind of thing in your tests:
user = login!
...or just:
login!
...at the top of a test.
You can also do:
login!(:admin => true)
...to log in as an admin.
So, that creates the user and logs them in. The bang just helps to keep the method short while also indicating that there's something extra going on.
hehe - I should really do a blog post about this...
P.S. your OpenID sign-in isn't working for me.
I did a little write-up about this:
February 12, 2009 at 4:15 PMhttp://almosteffortless.com/2009/02/12/the-login-test-helper-for-restful-authentication-and-machinist/
My coworker talked about it with me, and he made a good point. This bang seems appropriate in this case because it's changing the context and state.
I take a cue from the bang methods in the rails API and generally have them throw an exception if things go wrong as well. So hit! would be implemented as:
The other guideline I work by is that finder methods with bangs will throw an exception if they don't find anything, but that's now in Rails core so I can get rid of a bunch of custom made finders. Hurrah. February 13, 2009 at 10:05 AM