Search code examples
rubywebformsmechanize

Couldn't identify form using string 'post' but 'POST'. html contains 'post'


The code that didn't work:

login_form = page.form_with(:method => 'post')

and code that works:

login_form = page.form_with(:method => 'POST')

I inspected the form object via puts page.forms.inspect and got

[#<WWW::Mechanize::Form
 {name nil}
{method "POST"}
....]

html source:

<form class="login" method="post"> <fieldset>
<legend>Members Login</legend> 

<div>
<label for="auth_username">Username</label> <input id="auth_username" name="auth_username">
</div>

<div>
<label for="auth_password">Password</label> <input id="auth_password" name="auth_password" type="password">
</div>

</fieldset>
<div class="buttons">
<input name="auth_login" type="submit" value="Login"><p class="note"><a href="/forgotpassword">Forgot your password?</a></p>

</div>

</form>

Is this a bug or intended behaviour?


Solution

  • Looking at the source, it could be that Mechanize is supposed to work like that. It forces the form method to uppercase when it fetches the form; you are expected to supply the method in uppercase when you want to match it. You might ping the mechanize person(s) and ask them if it's supposed to work like that.

    Here in Mechanize.submit, it forces the form method to uppercase before comparing it:

    def submit(form, button=nil, headers={})
      ...
      case form.method.upcase  
      when 'POST'
        ...
      when 'GET'
        ...
      end
      ...
    end
    

    and here again in Form.initialize, the method is forced to uppercase:

      def initialize(node, mech=nil, page=nil)
        ...
        @method           = (node['method'] || 'GET').upcase
    

    But in page.rb is the code where mechanize is matching a form (or link, base, frame or iframe) against the parameters you gave, the parameter you passed in is not forced to uppercase, so it's a case sensitive match:

          def #{type}s_with(criteria)
            criteria = {:name => criteria} if String === criteria
            f = #{type}s.find_all do |thing|
              criteria.all? { |k,v| v === thing.send(k) }
            end
            yield f if block_given?
            f
          end
    

    Well, it's a case sensitive match if you pass in a string. But if you pass in a regex, it's a regex match. So you ought to be able to do this:

    login_form = page.form_with(:method => /post/i)
    

    and have it work fine. But I would probably just pass in an uppercase String, send the Mechanize person(s) an email, and move on.