Generic-user-small Paul Covell 5 posts

I am building a search query and so I would like the behavior to be like this:


GET /products/search --> index page + search input box
GET /products/search?keyword=blah&category=blah --> search results + refine search 
GET /products/search?keyword=blah&category=blah&page=3 --> 3rd page, for example

Products is RESTful, so I also use GET /products/<id>/show &c.

routes.rb:

map.resources :products, :collection => { :search => :get }

products_controller.rb:


  def search
    @products = search_results ... # abridged
  end

search.fbml.erb:


  <% form_tag(search_products_url, :canvas => :true) %>
  <%= text_field_tag(:keyword, params[:keyword]) %>
  <% end %>

Generates HTML:


<form action="http://apps.facebook.com/**canvas**/products/search" canvas="true" method="post">
<input id="keyword" name="keyword" type="text" />
</form>

Which, when data is entered, generates a GET to my application (dev log)


Processing ProductsController#search (for 127.0.0.1 at 2008-09-05 12:24:29) [GET]
 Parameters: {"fb_sig_time"=>"1220588633.3177", "category"=>"All", "fb_sig"=>"***", "fb_sig_in_new_facebook"=>"1", "_method"=>"GET", "fb_sig_locale"=>"en_US", "action"=>"search", "fb_sig_session_key"=>"***", "fb_sig_position_fix"=>"1", "fb_sig_in_canvas"=>"1", "fb_sig_request_method"=>"GET", "controller"=>"products", "fb_sig_expires"=>"1220675030", "fb_sig_added"=>"1", "fb_sig_friends"=>"<snip>", "fb_sig_api_key"=>"***", "keyword"=>"share", "fb_sig_user"=>"***", "fb_sig_profile_update_time"=>"1214711945"}

Finally leading to the error:


Facebooker::Session::IncorrectSignature (Facebooker::Session::IncorrectSignature):
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:103:in `verify_signature'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:88:in `verified_facebook_params'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:32:in `facebook_params'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:72:in `capture_facebook_friends_if_available!'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:25:in `set_facebook_session'
    /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/core_ext/object/misc.rb:28:in `returning'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:23:in `set_facebook_session'
    /vendor/plugins/facebooker/lib/facebooker/rails/controller.rb:167:in `ensure_authenticated_to_facebook'
I am open to other ways of doing it, but I do like having the search parameters in the URL for bookmarking/sending to others.
  • If I reclassify “search” as a “post” in routes.rb then it will work but I have to use another action for the index page and I lose the URLs.
  • If I create a new action “search-update” as a “POST” and then redirect to “search” as a GET, this will work (and it keeps the URL), but it seems both inefficient and fragile.

Is there a correct recipe for this behavior? I assume other people are building searches or other form input not directly related to an ActiveRecord object, so I think more treatment would be generally valuable. In this case, it would be nice to know more about what’s going on under the hood in Facebooker—I know that it is doing some magic to make RESTful routes work in the first place. My next stop is to read the code, but I was hoping to avoid this.

Thanks for any help.

Cheers,
-Paul

 
Generic-user-small Paul Covell 5 posts

Ok I have solved the IncorrectSignature error explained above.

The error can be reproduced by using :method => :get in the form_tag (in my case it was instead an unclosed form tag earlier on causing a get request—but the results are the same).

The workaround for getting search terms into the URL seems to be a redirect within the action:


def search
  if request.post?
    redirect_to search_products_url(:keyword => params[:keyword])
    return
  end

  ...
end

This may be unavoidable given the structure of:

Browser <> Facebook <> App

Anyone confirm this?

 
Head_small Mike Mangino 148 posts

I think the problem is in a slightly different place than you think. Your form is generating a POST form.

You showed the code:


 <% form_tag(search_products_url, :canvas => :true) %>
  <%= text_field_tag(:keyword, params[:keyword]) %>
  <% end %>

What you probably want is:


 <% form_tag(search_products_path, :method=>"get") do %>
  <%= text_field_tag(:keyword, params[:keyword]) %>
  <% end %>

Using search_products_url would work as well. (You don’t need to specify :canvas=>true. If the request is from a canvas page, the URL will be for a canvas page)

By default, form_tag creates posts. If you want it to use gets, you need to specify the method.

 
Generic-user-small Paul Covell 5 posts

Mike, sorry I wasn’t clear earlier—when I use :method => :get I get the IncorrectSignature exception.
The reason I was getting it on get OR post earlier was because of a bad tag in my HTML.

I tried your suggestion to verify, and the error is exactly the same. If I remove :method => :get to get the POST method, it works fine (but I don’t get my bookmarkable URLs—if I want those, I can do the redirect trick above, caveat as stated). This is probably some special case not caught in Facebooker, but I am shying away from that code (scary..)

Now I’m on to a slightly different topic, still forms-related: I’ve gotten all this to work before with PHP, so I’m familiar with how it should work but I’m having a tough time getting good information on how to do it with Facebooker/Rails:

- I’m trying to load a friend’s profile data for viewing and I need a dialog box to select the “target” friend. I successfully coded it up before as a FBJS new Dialog.showChoice(‘Select Target’, choose_target_dialog) with choose_target_dialog as a js-string. Now I’ve got a snag : I need to post to <my-server>/url, not <facebook>/url, but I don’t know how to get that URL. There aren’t any examples anywhere (at least with a bit of Googling) covering this kind of usage AFAICT.

Cheers, and thanks again.

 
Head_small Mike Mangino 148 posts

your_named_route(:canvas=>false) will give you a URL that points to the server.

In your previous example, can you provide a simple testcase that gives an invalid signature exception? I’m the maintainer of Facebooker and I’d love to get that fixed.

Mike

 
Generic-user-small Paul Covell 5 posts

Mike, I’ve managed to re-create this with a basic installation:

rails test
cd test
script/plugin install git://github.com/mmangino/facebooker.git
ruby script/generate controller home index search

views/home/index.fbml.erb:


<h1>Home</h1>
<% form_tag(url_for(:action => :search), {:method=>:get}) do %>
<p><%= text_field_tag(:keyword, params[:keyword]) %></p>
<p><fb:submit>Go</fb:submit></p>
<% end %>

app/controller/application.rb—added immediately below helper :all

  ensure_application_is_installed_by_facebook_user
  ensure_authenticated_to_facebook

And then I set up my development server and tunnel as I do with normal development. The error is the same. Also, if I remove the :method => :get, the error does not occur.

If you like I can send files to the mailing list or to you on the facebooker-talk list.

-Paul

 
Head_small Mike Mangino 148 posts

Yuck.

I see the same issue, but I don’t know why. In the short term, I’d say you can just use POSTS for this. I’ll keep trying to figure this out and get it fixed.

Mike

 
Generic-user-small Christopher ... 5 posts

I’m having the exact same problem. Let me know if you figure anything out!

 
Head_small Mike Mangino 148 posts

Can you guys report this to the facebooker mailing list? I’m going to keep trying to figure it out, but maybe another couple of eyes would be helpful.

Mike

 
Generic-user-small Paul Covell 5 posts

Posting now.

10 posts, 3 voices