Fixing CSRF and Rails’ Form Tag Helper

I’d love a sanity check on this, but as far as I can tell it’s impossible to have an inline form in Rails if you are using cross site request forgery protection.

Rails’ form tag helper helpfully puts a hidden field in with an authenticity token. Unfortunately, it wraps the hidden field in a div! So even if your form has style=”display:inline”, the div won’t.. and you won’t be able to display a form that doesn’t force a newline.

Here’s a solution: create config/initializers/fix_form_tag_helper.rb to override the form_tag_helper:

module ActionView::Helpers::FormTagHelper
  def extra_tags_for_form(html_options)
    case method = html_options.delete("method").to_s
    when /^get$/i # must be case-insentive, but can't use downcase as might be nil
      html_options["method"] = “get”
      ”
    when /^post$/i, “”, nil
      html_options["method"] = “post”
      #Rails puts a div around the hidden tag, that’s ridiculous
      #protect_against_forgery? ? content_tag(:div, token_tag, :style => ‘margin:0;padding:0′) : ”
      protect_against_forgery? ? token_tag : ”
    else
      html_options["method"] = “post”
      #Rails puts a div around the hidden tag, that’s ridiculous
      #content_tag(:div, tag(:input, :type => “hidden”, :name => “_method”, :value => method) + token_tag, :style => ‘margin:0;padding:0′)
      tag(:input, :type => “hidden”, :name => “_method”, :value => method) + token_tag
    end
  end
end

That does the trick!

6 comments ↓

#1 Eric Anderson on 10.14.08 at 1:25 pm

Could you just do

.form, .form div {display: inline}

Haven’t tried it myself. Just my first thought.

#2 Luke Galea on 10.14.08 at 1:29 pm

Ah! But that makes all divs below forms display inline. In my case, some forms should display inline and others shouldn’t.

If there were an id or class on the div then that would make things nice, but otherwise you run the risk of inlining divs that should actually be display:block.

You could also look for the first div below a form, but then if disable CSRF (ie. in development mode) then it fails.

After some “soul searching” I decided that it should either be a span with a class/id or not there at all.

#3 Adam on 10.14.08 at 7:18 pm

It puts a div around the hidden tags as they are required by the html dtd (http://www.w3.org/TR/REC-html40/interact/forms.html#edef-FORM)
A form element can only contain block or script elements.

So instead of invalidating your html why didn’t you just make it add a class to the div so you can style your forms the way you want.

form.inline { display:inline }
form div.secret-squrrel { display:inline; margin:0; padding: 0; }

would be better don’t you think?

#4 Luke Galea on 10.14.08 at 7:55 pm

Good call. I had no idea they were required by the dtd.

Adding a class is much better in that case. Thanks Adam.

#5 Alex Gordon on 04.01.10 at 10:10 pm

здрасте всем!!!!!!!!!!…

Менеджер по обучению персонала, тренинг менеджер Rails’ form tag helper helpfully puts a hidden field in with an authenticity token. Unfortunately, …

#6 Kylie Batt on 05.12.10 at 9:04 pm

Вас посетила просто отличная идея…

Начальник отдела продаж, менеджер Rails’ form tag helper helpfully puts a hidden field in with an authenticity token. Unfortunately, it wraps the hidden field in …

You must log in to post a comment.