Product Filter

234 views
Skip to first unread message

John Polling

unread,
Jul 23, 2010, 12:38:25 PM7/23/10
to Spree
Hi,

I'm currently working on a project which uses Spree 0.10.2 and I need
to use product filters. I've taken a copy of the lib/
product_filter.rb file and placed it in my Spree project. I've just
done a quick test and the filters appear fine, however as soon as I
click on one of the filters I'm getting errors like this:

undefined method `each_pair' for "price_range2_anyUnder £10£10 -
£15":String

I've not used Spree before so not certain what I'm doing wrong.

Can someone please point me in the correct direction.

Thanks

John

Marcin Raczkowski

unread,
Jul 24, 2010, 6:34:59 AM7/24/10
to spree...@googlegroups.com

Somewhere (I can't tell you where exactly without full trace) You're
passing string instead of array - first thing would be to remove any
susspicious .to_s right before method invocation.

John Polling

unread,
Jul 24, 2010, 4:48:22 PM7/24/10
to Spree
I think it's something I must be doing wrong.

When I click on one of the checkboxes the url that is being generated
is

http://0.0.0.0:3000/t/brands/ruby-on-rails?authenticity_token=4XY1QPxgrcinM2wcBsin75OS7kRRz3G54P133TrnVPs%3D&per_page=10&search=price_range_any£18+-+£20

Instead it should the search part should be

&search[price_range_any][£18+-+£20]

This now works a treat.

Andrea S.

unread,
Jul 25, 2010, 12:49:10 AM7/25/10
to Spree
Hi John,

I remember having a similar issue when I was trying to implement
Product Filters. It took me some fiddling around to make it work. I
actually didn't use Product Filters in the end, but I dug up the code
I used at the time to build the query string properly.

First check whether your view code is similar to this with the
"filter" variable being a particular Product Filter, such as
price_filter:

<% labels = filter[:labels] || filter[:conds].map {|m,c| [m,m]} %>
<% next if labels.empty? %>
<div class="navigation">
<span class="category"><%= filter[:name] %></span>
<ul style="list-style-type:none; padding-left: 0px;"
class="filter_choices">
<% labels.each do |nm,val| %>
<% label = "#{filter[:name]}_#{nm}".gsub(/\s+/,'_') %>
<li class="nowrap">
<%= check_box_tag "search[#{filter[:scope].to_s}][]",
val, (params[:search][filter[:scope]] && params[:search]
[filter[:scope]].include?(val.to_s)), {:id => label} %>
<label class="nowrap" for="<%= label %>"><%= nm %></
label>
</li>
<% end %>
</ul>
</div>

The checkbox should look like this:

<input id="Price_Range_Under_$10" name="search[price_range_any][]"
type="checkbox" value="Under $10" />

I think the problem that causes the query string to be built
incorrectly is in the SeoAssist class, which is a middleware located
in the app/metal/seo_assist.rb file. This class is responsible to
prettify urls for SEO purposes, e.g. when a taxon is present it would
redirect the query to /t/brand?#{query}.

There is a helper method in that class, called
self.build_query(params), that essentially takes the params hash and
converts it into a Rails compatible query string. That will become the
"query" variable that gets appended to the url.

This is where I needed to make a change, since in the case of a search
query the value is a hash (see below) and that case wasn't handled by
the method:

{"taxon"=>"2",
"authenticity_token"=>"kicSJ3kkizb6AhkhOFYJ2Tqoa46O9cNyrALIIwm20qk=",
"per_page"=>"15", "search"=>{"price_range_any"=>["Under $10", "$10 -
$25"]}}

This is the build_query method after I applied my modification:
def self.build_query(params)
params.map { |k, v|
if v.class == Array
build_query(v.map { |x| ["#{k}[]", x] })
# I added this to handle search query, i.e. search[key1]
[]=v1&search[key1][]=v2&search[key2]=v3
# if search param is present, then value is another hash, not an
array
elsif v.class == Hash
build_query(v.map {|hk, hv| ["#{k}[#{hk}]", hv]})
else
k + "=" + Rack::Utils.escape(v)
end
}.join("&")
end

After running through the build_query method, the query string should
look like this:

"authenticity_token=kicSJ3kkizb6AhkhOFYJ2Tqoa46O9cNyrALIIwm20qk
%3D&per_page=15&search[price_range_any][]=Under
+10&search[price_range_any][]=10+-+25"

Not sure whether the SeoAssist class is obsolete in newer versions of
Spree, but the modification seems to be necessary to get Product
Filters to work in older versions.

~ Andrea

On Jul 24, 10:48 am, John Polling <john.pollin...@googlemail.com>
wrote:
> I think it's something I must be doing wrong.
>
> When I click on one of the checkboxes the url that is being generated
> is
>
> http://0.0.0.0:3000/t/brands/ruby-on-rails?authenticity_token=4XY1QPx...18+-+£20

John Polling

unread,
Jul 25, 2010, 5:42:32 AM7/25/10
to Spree
Thanks Andrea,

In the end I ditched the product filter as I found Product Scopes to
do what I needed.

I ended up writing a filter_url_helper that helped me to to join
various scopes together.

http://gist.github.com/489452

My question to Spree experts is, are scopes the best way of product
filtering now? Is there a better way to build urls that the helper
I've written?

Thanks

John
> >http://0.0.0.0:3000/t/brands/ruby-on-rails?authenticity_token=4XY1QPx...20

Marcin Raczkowski

unread,
Jul 25, 2010, 12:47:44 PM7/25/10
to spree...@googlegroups.com
On 25.07.2010 11:42, John Polling wrote:
> Thanks Andrea,
>
> In the end I ditched the product filter as I found Product Scopes to
> do what I needed.
>
> I ended up writing a filter_url_helper that helped me to to join
> various scopes together.
>
> http://gist.github.com/489452
>
> My question to Spree experts is, are scopes the best way of product
> filtering now? Is there a better way to build urls that the helper
> I've written?
>
> Thanks
>
> John


Scopes are best way to do this now, check out promotions extension to
see example how to use them.

Reply all
Reply to author
Forward
0 new messages