1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
def link_to_param(text, param, values) @qs ||= {} if @qs.blank? request.query_string.split('&').each do |p| pair = p.split('=') @qs[pair[0]] = pair[1] end end qs = [] values = [values] unless values.is_a?(Array) value = values[0] param_value = values.blank? ? '' : "#{param}=#{values[0]}" if request.parameters[param] if values.include?(request.parameters[param]) css_class = 'current' @qs.each do |p, v| value_idx = 0 value_idx = request.parameters[param] == values[0] ? 1 : 0 if request.parameters[param] == v && values.size > 1 if p == param qs << "#{p}=#{values[value_idx]}" else qs << "#{p}=#{v}" end end else qs << "#{param}=#{value}" unless value.blank? @qs.each do |p, v| qs << "#{p}=#{v}" unless p == param end end else if value.blank? css_class = 'current' else qs << "#{param}=#{value}" end @qs.each do |p, v| qs << "#{p}=#{v}" unless p == param end end qs = qs.sort.join('&') link_to text, "?#{qs}", :class => css_class end
Refactorings
No refactoring yet !
lel
July 18, 2008, July 18, 2008 00:34, permalink
You should always avoid building url:s or parsing query strings by yourself. It is not the first time it's ever needed so there are ways in the framework to deal with this already. And then the pieces go together very nice resulting in reduced and maintainable code.
Also, if a method exceeds any of the approximate limits of 80 columns, 25 lines or three levels of indentation, you need to stop and maybe reconsider your approach :-)
My example may not be what you want, since I introduced a specific param for the order (to avoid further parsing of the sort_by down the line). But it's a starting point: use params hash to get qs, and use link_to's ability to take the same kind of hash.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# Example: link_to_toggle_asc_desc("text", {:sort_by => "name", :filter_by => "x"}) # Produces: ?sort_by=name&filter_by=x&order=asc (order is automatically added) # Order will auto toggle every time you click the link, and any other query string params # not overridden by the options you pass in will be preserved. def link_to_toggle_asc_desc(text, opts={}) if params[:order] == "desc" opts[:order] = "asc" else opts[:order] = "desc" end link_to(text, params.merge(opts)) end # Try this: <%= link_to_toggle_asc_desc "first", {:sort_by => "name"} %> <%= link_to_toggle_asc_desc "second", {:filter_by => "x"} %>
Tien Dung
July 26, 2008, July 26, 2008 03:29, permalink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
## # Fun with if .. else assignment ;) # Change if params[:order] == "desc" opts[:order] = "asc" else opts[:order] = "desc" end # To # In Ruby, if .. then .. else .. end can return value opts[:order] = if params[:order] == "desc" "asc" else "desc" end # I prefer ternary operator in this case opts[:order] = params[:order] == "desc" ? "asc" : "desc"
In a Rails application, I have links that add params to filter or sort data, and I want that when one clicks on a link, the current params are kept.
This is my first attempt.
The way to use it is this:
link_to_param 'Link text', 'param_name', ['value1', 'value2'...]
The values argument is for either one value or several values (like sort flags, so if param_name = value1, then param_name = value2).
So if the query string looks like this:
?sort_by=name_asc
And I do this:
link_to_param 'Sort by name', 'sort_by', ['name_asc', 'name_desc']
link_to_param 'Show only X', 'filter', 'by_x'
Then the generated link's query string will be:
?sort_by=name_desc (first link)
?filter=by_x&sort_by=name_asc (second link)
And when the parameter is not included in the current query string, the first value in the array will be the default.
Is there an easier way to accomplish this?
Comment: Thanks for your refactorings, but I think you didn't quite get what I'm trying to accomplish... Thanks anyway.