Passing array in params via xhr

Hey all,

I’m writing some functional tests for some drag-sort stuff, and I can’t seem to figure out how to pass an array in as part of my params in the xhr method.

My code is the typical simple stuff that just reorders a set to match the order of the ids passed in:

def reorder_stuff
@stuff = Stuff.find(params[:stuff_id])
@stuff.active_widgets.each do |widget|
widget.position = params[:widgets].index(widget.id.to_s) + 1
widget.save
end

render :nothing => true

end

When I try to simulate the post, I’m using the following:

xhr :post, :reorder_stuff, {:stuff_id => 1, :widgets => [3,1]}

I get a nil reference error when I run this, and I get the following error if I try to put the contents of params[:widgets] to stdout:

TypeError: can’t convert ActionController::Routing::PathSegment::Result into String

So, it seems that the array isn’t making it through routing, which makes sense. But I’m at a bit of a loss as to how to get an array in any other way as part of params. Since it’s a hash, I can’t pass it in the same way that it arrives via the request: “widget[]=1&widget[]=3” since it would have duplicate keys.

Any help would be greatly appreciated!

Thanks,

I think this should work:

xhr :post, :reorder_stuff, {:stuff_id => 1,
     :widgets => {:a => 1, :b =>3} }

because that should create params[:widgets][]. But there's probably a
better way

Thanks for the idea! It kind of works, and I actually get a hash instead of it getting mangled by routing.

Unfortunately I need it as an array so I can call index on it to get the correct order… I could change the implementation, but then I’m basically writing it one way for the test and one way for the real world.

Thanks for the help! Any other ideas? :wink: I’ve spent all afternoon on this, and I’m sure I’m missing something really obvious…

Matt

I think you could make it behave like an array by tricking it:
xhr :post, :reorder_stuff, {:stuff_id => 1,
     :widgets => {0 => 1, 1 =>3} }

Matt White wrote:

Thanks for the idea! It kind of works, and I actually get a hash instead of
it getting mangled by routing.

Unfortunately I need it as an array so I can call index on it to get the
correct order... I could change the implementation, but then I'm basically
writing it one way for the test and one way for the real world.

What's the view-side code look like?

Phlip,

<% @stuff.active_widgets.each do |w| %> <%= render :partial => "account/stuff/widget", :locals => { "w" => w } %>
<% end %>   
<%= sortable_element("widgetlist", :tag => "div", :url => { :controller => "stuff", :action => "reorder_widgets", :stuff_id => @

stuff.id }) %>

The request that makes it to Rails looks like: “albums%5B%5D=3&albums%5B%5D=1&=", or "albums[]=3&albums[]=1&=”. It’s the same thing you do with a HABTM relationship managed via a select tag. But, I’ve just never actually tried to test this before.

Thanks!

Matt

Matt White wrote:

<div id="widgetlist">
   <% @stuff.active_widgets.each do |w| %>
       <%= render :partial => "account/stuff/widget", :locals => { "w" => w
} %>

Is everyone calling partials out of views as a twisted way to functionalize a block of stuff that we don't want to type inline into long blocks?

I only use them when a view and AJAX will re-create the same stretch of HTML. I use Builder::XmlMarkup to create lots of little functions that create the intermediate HTML.

I can't help with the sortable list because I'm only up to page 27 in /Rails Recipes/, and I can't tell if the book explains exactly how all the monotonically numbered IDs in the HTML list get transferred into the AJAX parameters...

   <% end %>
   <%= sortable_element("widgetlist", :tag => "div", :url => { :controller
=> "stuff", :action => "reorder_widgets", :stuff_id => @stuff.id }) %>
</div>

The request that makes it to Rails looks like:
"albums%5B%5D=3&albums%5B%5D=1&_=", or "albums[]=3&albums[]=1&_="

Thanks but I just meant to --> p params <-- it, so we see what the controller sees. Not the raw query string. No worries.

The problem is that it’s obvious enough what the controller sees at the end. It’s an array of integer id’s, the same as if you were to use

select “model”, “attribute[]”, choices, :multiple => true

to get params[:attribute] in as an array of values.

The sortable list itself works just fine, so my issue isn’t there… It’s how to functionally test it because I can’t see how to pass an array parameter into the controller via xhr because an array passed in gets mangled by the routing…

And yeah, I use partials because I re-render that particular bunch all over the place. It’s more DRY.

Matt

Hey all,

I walked away from this one and came back a few days later… I thought I’d check the ActionPack test code to see what they do, and in cgi_test I found the answer…

When you pass in variables, don’t pass in integers:

xhr :get, :reorder_widgets, {:widget_id => 1, :widgets => [‘1’,‘3’]}

instead of

xhr :get, :reorder_widgets, {:widget_id => 1, :widgets => [1,3]}

All the request parsing code in cgi_test uses strings, no integers.

Matt