Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails form validation

Tags:

I have a Rails app that lets a user construct a database query by filling out an extensive form. I wondered the best practice for checking form parameters in Rails. Previously, I have had my results method (the one to which the form submits) do the following:

if params[:name] && !params[:name].blank?   @name = params[:name] else   flash[:error] = 'You must give a name'   redirect_to :action => 'index'   return end 

But for several form fields, seeing this repeated for each one got tiresome. I couldn't just stick them all in some loop to check for each field, because the fields are set up differently:

  • a single key: params[:name]
  • a key and a sub-key: params[:image][:font_size]
  • only expect some form fields to be filled out if another field was set

Etc. This was also repetitive, because I was setting flash[:error] for each missing/invalid parameter, and redirecting to the same URL for each one. I switched to using a before_filter that checks for all necessary form parameters and only returns true if everything's okay. Then the my results method continues, and variables are just assigned flat-out, with no checking involved:

@name = params[:name] 

In my validate_form method, I have sections of code like the following:

if (   params[:analysis_type][:to_s] == 'development' ||   params[:results_to_generate].include?('graph') )   {:graph_type => :to_s, :graph_width => :to_s,    :theme => :to_s}.each do |key, sub_key|     unless params[key] && params[key][sub_key]       flash[:error] = "Cannot leave '#{Inflector.humanize(key)}' blank"       redirect_to(url)       return false     end   end end 

I was just wondering if I'm going about this in the best way, or if I'm missing something obvious when it comes to parameter validation. I worry this is still not the most efficient technique, because I have several blocks where I assign a value to flash[:error], then redirect to the same URL, then return false.

Edit to clarify: The reason I don't have this validation in model(s) currently is for two reasons:

  • I'm not trying to gather data from the user in order to create or update a row in the database. None of the data the user submits is saved after they log out. It's all used right when they submit it to search the database and generate some stuff.
  • The query form takes in data pertaining to several models, and it takes in other data that doesn't pertain to a model at all. E.g. graph type and theme as shown above do not connect to any model, they just convey information about how the user wants to display his results.

Edit to show improved technique: I make use of application-specific exceptions now, thanks to Jamis Buck's Raising the Right Exception article. For example:

def results   if params[:name] && !params[:name].blank?     @name = params[:name]   else     raise MyApp::MissingFieldError   end    if params[:age] && !params[:age].blank? && params[:age].numeric?     @age = params[:age].to_i   else     raise MyApp::MissingFieldError   end rescue MyApp::MissingFieldError => err   flash[:error] = "Invalid form submission: #{err.clean_message}"   redirect_to :action => 'index' end