One little gem from the standard library that I only discovered a few months ago is the OpenStruct. An OpenStruct is just a hash with a method interface. That is open_struct.attribute is functionally similar to hash.attribute.
First things first, you gotta require it:
require'ostruct'#In environment.rb or maybe a shiny initializer
Now why would I want anything but a hash? After all, I come from PHP where almost everything is an (ordered) hash, and it’s one of the few features of the language that I actually find useful, language purism aside.
For me the killer app of OpenStruct is for Rails forms that aren’t backed by models. You should already know that you don’t need a database table behind every model, but sometimes even a model is overkill. An example would be a simple contact form. Your action might look like this:
def contact
if request.post?
@contact= OpenStruct.new(params[:contact])
if@contact.email.blank?
flash.now[:error] ="Please fill out your email address."else
Notifier.deliver_contact(@contact)
flash[:notice] ="Your message was sent."
redirect_to ""endendend
This allows you to use form_for on @contact, which gives you form persistence much more elegantly than manually cramming values back into raw text_fields.
Some might argue that the form validation criteria should be in a model, which I would agree with in more complex cases. But here the condition is so simple that moving it into a model would only add to the complexity of the architecture. If the validation criteria do get more complex we can easily refactor later.
If I were to refactor, I’d subclass my model from OpenStruct. That makes the form more flexible, because I don’t need to explicitly add fields to the model. I can just stick them in the form as necessary; OpenStruct doesn’t cry over missing methods. The one weakness is that OpenStruct doesn’t provide a public method to return its keys. If you want to make a generic form processor, I recommend only using the OpenStruct for the controller and view, but passing the params hash into your ActionMailer.
If you’re really in a pinch you can illegally dip into Ruby internals with @contact.send(:table).keys, but you didn’t hear that from me.
OpenStructs for Rails Forms Instead of Models
One little gem from the standard library that I only discovered a few months ago is the
OpenStruct
. AnOpenStruct
is just a hash with a method interface. That isopen_struct.attribute
is functionally similar tohash.attribute
.First things first, you gotta require it:
Now why would I want anything but a hash? After all, I come from PHP where almost everything is an (ordered) hash, and it’s one of the few features of the language that I actually find useful, language purism aside.
For me the killer app of
OpenStruct
is for Rails forms that aren’t backed by models. You should already know that you don’t need a database table behind every model, but sometimes even a model is overkill. An example would be a simple contact form. Your action might look like this:This allows you to use
form_for
on@contact
, which gives you form persistence much more elegantly than manually cramming values back into rawtext_fields
.Some might argue that the form validation criteria should be in a model, which I would agree with in more complex cases. But here the condition is so simple that moving it into a model would only add to the complexity of the architecture. If the validation criteria do get more complex we can easily refactor later.
If I were to refactor, I’d subclass my model from
OpenStruct
. That makes the form more flexible, because I don’t need to explicitly add fields to the model. I can just stick them in the form as necessary;OpenStruct
doesn’t cry over missing methods. The one weakness is thatOpenStruct
doesn’t provide a public method to return its keys. If you want to make a generic form processor, I recommend only using theOpenStruct
for the controller and view, but passing the params hash into yourActionMailer
.If you’re really in a pinch you can illegally dip into Ruby internals with
@contact.send(:table).keys
, but you didn’t hear that from me.