This question already has answers here:
Add querystring parameters to link_to
(5 answers)
Closed 8 years ago.
I have a logic where I allow sorting on price and relevance. I am doing this by passing parameters to controller. My URL has a parameter - 'sort' which can have a value - 'price_lowest' or 'default'.
The links looks like:
lowest prices |
relevance
problem with the above code is that it "adds" parameters and does not "replace" them. I want to replace the value of &sort= parameter without adding a new value. E.g. I don't want :
../&sort=price_lowest&sort=price_lowest&sort=default
With the current logic - I am getting the above behaviour. Any suggestions ?
In order to preserve the params I did this:
<%= link_to 'Date', params.merge(sort: "end_date") %>
However the url will be ugly.
UPDATE
For Rails 5 use:
<%= link_to 'Date', request.params.merge(sort: "end_date") %>
If you only need one cgi param and want to stay on the same page, this is very simple to achieve:
<%= link_to "lowest prices", :sort => "price_lowest" %>
However, if you have more than one, you need some logic to keep old ones. It'd probably be best extracted to a helper, but essentially you could do something like this to keep the other params..
<%= link_to "lowest prices", :sort => "price_lowest", :other_param => params[:other] %>
Named routes will only really help you here if you need to go to another page.
If a path is not passed to the link_to method, the current params are assumed. In Rails 3.2, this is the most elegant method for adding or modifying parameters in a URL:
<%= link_to 'lowest prices', params.merge(sort: 'end_date') %>
<%= link_to 'relevance', params.merge(sort: 'default') %>
params is a Ruby hash. Using merge will either add a key or replace the value of a key. If you pass nil as the value of a key, it will remove that key/value pair from the hash.
<%= link_to 'relevance', params.merge(sort: nil) %>
Cite:
link_to http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to
url_for
http://apidock.com/rails/v3.2.13/ActionView/Helpers/UrlHelper/url_for
My working solution on Rails 3.1
of course, it's hardcode, and has to be refactored.
item model
def self.get(field,value)
where(field=>value)
end
items controller
#items=Item.all
if params[:enabled]
#items=#items.get(:enabled, params[:enabled])
end
if params[:section]
#items=#items.get(:section_id, params[:section])
end
items helper
def filter_link(text, filters={}, html_options={})
trigger=0
params_to_keep = [:section, :enabled]
params_to_keep.each do |param|
if filters[param].to_s==params[param] && filters[param].to_s!="clear" || filters[param].to_s=="clear"&¶ms[param].nil?
trigger=1
end
if filters[param]=="clear"
filters.delete(param)
else
filters[param]=params[param] if filters[param].nil?
end
end
html_options[:class]= 'current' if trigger==1
link_to text, filters, html_options
end
items index.html.erb
<%= filter_link 'All sections',{:section=>"clear"} %>
<% #sections.each do |section| %>
<%= filter_link section.title, {:section => section} %>
<% end %>
<%= filter_link "All items", {:enabled=>"clear"} %>
<%= filter_link "In stock", :enabled=>true %>
<%= filter_link "Not in stock", :enabled=>false %>
It's not quite the answer to the question that you're asking, but have you thought about using the Sorted gem to handle your sorting logic and view links?
Related
I have two forms that leads to one controller action:
<%= form_tag some_action_path do %>
<%= slect_tag 'foo[]', options_for_select([
["Nothing", nil],
["wal1", "wal1"],
["wal2", "wal2"]]) %>
<%= submit_tag "Search" %>
<% end %>
<%= form_tag some_action_path do %>
<%= check_box_tag 'foo[]', "wal1" %>
<%= check_box_tag 'foo[]', "wal2" %>
<%= submit_tag "Search" %>
<% end %>
My problem is that when I select "Nothing" in select select_tag I get [""], on the other hand when I submit second form without any check_box selected I get nil. Which gives me a headake in my search function. Because it have to look like this:
def search_action(foo)
if foo.nil?
Obj.all
elsif foo.present? && foo[0].blank?
Obj.all
elsif foo.present? && foo[0].pesent?
Obj.where(foo: foo)
end
end
The function above is irrelewent, I only wanted to show how the difference output between those two forms complicate my search action.
My question:
Is there any way to return nil from "select_tag" form? Or I am stupid to lead two forms to one controller action and one search method, and I should write two actions with two search action that leads to one view. :D
Usually the search functionality is in one form where you have the both options available, but there is nothing wrong with your approach if you want them to be separate searches. Though I would rename the input of either of the forms to not be same as the other forms inputs to differentiate them on controller and then be able to write something like
def search_action(foo)
if form_1_attribute.present?
Obj.where(form_1_attribute: form_1_attribute)
elsif form_2_attribute.present? && form_2_attribute.blank?
Obj.where(form_2_attribute: form_2_attribute)
else
Obj.all
end
end
I used to have a link that lead to a search action and carried certain parameters. This was the link (for example):
<%= link_to "search", discover_search_url(:category_id => 3) %>
A friend of mine refactored the site and did a fantastic job of it, but now the category_id is inside a parent hash called pieces_search. So instead of using params[:category_id] now I use params[:pieces_search][:category_id].
My question is, how do I modify my link now?
<%= link_to "search", discover_search_url(:pieces_search => {:category_id => 3}) %>
Ive got a select_tag field at the top of a page and trying to get the selected option to change the content on the page based on the users selection.
Im a learner and have found pieces of information around but without detailed examples and good explanations on how to best approach and implement.
The scenario is as follows:
I have a belongs_to association between a project and documents and in one of my views which lists documents, I want to only show all the documents that belong to the currently selected project in the select tag.
Passing the selected project's id to the documents index action which only shows documents for a specified project id via a link_to tag came to mind. This would thus refresh the page with the correct documents in the view but I believe that is not the correct way to do it and that I cant use link_to tags as options in a select_tag. Can anyone help and offer an example?
I would suggest using the form.select method and options_for_select as in
f.select :attribute, options_for_select(#array, default_value)
and in your controller you should create or update using the submitted parameter
n = record.new(:attribute => params[:attribute])
have fun
In your controller:
def index
if params[:project]
#documents = Document.where(:project => params[:project]
else
#projects = Project.all
end
end
In your form/view:
<%= form_tag 'projects', :method => :get do %>
<%= options_from_collection_for_select(#projects, :id, :name)
<%= submit_tag %>
<% end %>
<% if #documents %>
<%= #documents.each do |d| %>
....
<% end >
<% end %>
I am relatively new to rails. I am using a partial like a ui component, to call certain controllers. Here is something that I have in shared/post_button.html.erb and I pass in params while rendering the partial, like controller and action OR the path.
<%
path = "" if !path
action = "" if !action
controller = "" if !controller
values = {} if !values
%>
<%= form_tag(path, :controller => controller, :action => action, :method => "post") do %>
<%= hidden_field_tag(:values, values) %>
<%= submit_tag label %>
<% end %>
I am using this way to call certain controllers via POST using a form (instead of a link_to passing variables) because I figured that was a more secure way of posting certain records in to the DB. Comments welcome to let me know if there is a better method or syntax to go about doing this.
Now, my question is: What I am trying to do here is have an ability to pass in a values object containing all sorts of values I'd like to receive at the controller end. At the moment, the values tag doesn't seem to work. How do I go about passing in objects/values to the controller? Do I need to append it to the URL? The way I am using this partial, I sometimes do not pass in the url and pass in a controller and action variable, how would I go about passing values then?
Are you looking for something like this?
<%= form_tag(path, :controller => controller, :action => action, :method => "post") do %>
<% values.each_pair do |k,v| %>
<%= hidden_field_tag(k, v) %>
<% end %>
<%= submit_tag label %>
<% end %>
Where you iterate over each key/value pair in your values hash to submit them as individual parameters.
In the application there is a default report the user see's listing all the calls for a certain phone. However, the user can select a date range to sort the list from. Doing that, everything works correctly, but when the user selects the date range and changes to the second page, the date-range is lost and it goes back to the default view for the second page.
In my controller, I'm checking to see if the date_range param is being passed in. If it isn't, I display the entire listing, if it is, I display the records in between the certain date range.
The problem is, when I click on a new page, the new parameter doesn't include the old date-range that it should.
How do I go about doing this, I was thinking of doing some class level variable test but that isn't working out the way I thought. And I'm pretty stuck.
I don't have the code right in front of me, but if I remember correctly it's something like this:
<% form for :date_range do |f| %>
<%= f.calendar_date_select :start %>
<%= f.calendar_date_select :end %>
<%= f.Submit %>
<% end %>
And in the controller, it's something like:
if params[:date_range] == nil
find the complete listings without a date range
else
find the listings that are within the date range
end
The main problem is that you're using a POST request when submitting the form, but will-paginate uses a GET request. You should also use form_tag instead of form_for because form_for will nest the fields in a hash which is not possible with GET.
<% form_tag items_path, :method => 'get' do %>
<%= calendar_date_select_tag :start_date %>
<%= calendar_date_select_tag :end_date %>
<%= submit_tag "Submit", :name => nil %>
<% end %>
Then check params[:start_date] and params[:end_date] directly. You'll need to change items_path to whatever page you want the form to go to.
This is untested but it should get you in the right direction.
You could modify the link_to (assuming that's how you go through pages) so that it passed the date_range param.
= link_to 'Next', #whatever_path, :date_range => #date_range
where #date_range could be set in your controller by capturing your params in an instance variable.. .
But there may be a better solution.