In my Rails app I have a simple form that filters all the user's invoices by date:
<%= form_tag invoices_path, :method => 'get' do %>
<%= text_field_tag :date, params[:date] %>
<%= submit_tag "Search" %>
<% end %>
When a user enters a date in his preferred date format, e.g. 27/07/2014, I want this to be shown in the URL as /invoices?date=2014-07-14 because this can be handled much more easily by the database and also looks better than /invoices?date=25%2F07%2F2014.
Is there any way to convert a GET parameter like this in Rails?
Thanks for any help.
First of all, the date prettifying is to be done on the client side, since you want the pretty value to be shown in the query params already.
The form_tag may be supplied with onsubmit callback:
<%= form_tag invoices_path,
:method => 'get'
:onsubmit => 'return validate(this)' do %>
Here validate() would be a javascript validation method that would return true or false; you are free to prettify and overwrite the date value there.
Probably there is a more elegant way to accomplish that, but the aforementioned one worked well for me. Hope it helps.
Related
I have the following form
<%= form_for :key, url: unblock_keys_path, :html => {:method => :get} do |f| %>
<%= f.text_field :value %>
<%= button_to "Unblock", method: :get %>
<% end %>
Which works fine when I enter key values in the text box. But i want the user to be able to access the endpoint directly from the url as well.
Right now the params this request generates are:
{"utf8"=>"✓", "key"=>{"value"=>"x0vdPYWb9nAfyNjFS-UAGQ"},
"authenticity_token"=>"+Oi45DHYpPAiNbKrw5kNjWMVrQgCyLsBkhVb7huB0dr+xm/oKXxzTShajVUYEWxl9qlFLfjWsP4C4JM30DTGoA==",
"controller"=>"keys", "action"=>"unblock"}
url: http://localhost:3000/keys/unblock?utf8=✓&key%5Bvalue%5D=x0vdPYWb9nAfyNjFS-UAGQ&authenticity_token=%2BOi45DHYpPAiNbKrw5kNjWMVrQgCyLsBkhVb7huB0dr%2Bxm%2FoKXxzTShajVUYEWxl9qlFLfjWsP4C4JM30DTGoA%3D%3D
I want to be able to access localhost:3000/keys/unblock?<key_value>
What changes do I need to make in my request and routes?
This localhost:3000/keys/unblock?<key_value> is not a valid url*. The ? denotes the start of the params, and then everything after that needs to have the form "name=value", joined with "&".
Do you mean localhost:3000/keys/unblock/<key_value>?
If so then add a route like
get '/keys/unblock/:value', to: 'keys#unblock'
This will send eg /keys/unblock/foo to your unblock action, with params[:value] = "foo"
*note - technically it's not illegal, but it's poorly formed and almost certainly not what you want to do.
Let's assume I have this simple search form:
<%= form_tag invoices_path, :method => 'get' do %>
<%= text_field_tag :number %>
<%= text_field_tag :date %>
<%= text_field_tag :total %>
...
<%= submit_tag %>
<% end %>
This is my controller:
class InvoicesController < ApplicationController
def index
#invoices = current_user.invoices.search(params)
end
...
end
How can I omit certain parameters from the the params hash, e.g. the total?
I've tried things like params.except(:total), however that didn't change anything.
I don't want the total being sent to the search function, and I don't want it to appear in the URL either.
How can this be done?
Thanks for any help.
If the input is included in the form, it will be submitted with the form unless you take special action. By the time you get into Rails code on the server, it's too late.
One approach is to disable the element immediately before the form is submitted:
Add a never-submit class to your input:
<%= text_field_tag :total, '', :class => 'never-submit' %>
Then use jQuery to disable any elements with that class before the form is submitted:
$(document).ready(function() {
$('form').submit(function() {
$('.never-submit').prop('disabled', true);
return true;
});
});
You also may want to consider making the field something besides an input. Inputs are designed to allow users to submit data to your server. If that's not the intent of that field, something like a span (styled to look like an input) might be more appropriate.
Just doing
params.except(:total)
doesn't change the params hash, it just returns a changed hash. You can do it with the 'bang' like
params.except!(:total)
however changing the params hash is not recommended, as other actions might depend on it.
So this is the way to go for you.
filter = params.except(:total)
#invoices = current_user.invoices.search(filter)
params is a hash, so I think you can do this. Can you try this?
params.delete(:total)
#invoices = current_user.invoices.search(params)
I have this form:
<%= form_tag posts_path, :method => :get, :class => "search_nav" do %>
<%= text_field_tag :search, params[:search], :class => "input-long search-query", :placeholder => "#{t('.search_nav')}" %>
<%= hidden_field_tag('ip', "#{request.ip}") %>
<%= hidden_field_tag('city', "#{request.location.city}") %>
<%= hidden_field_tag('country', "#{request.location.country}") %>
<%= content_tag(:div, "",:class => "icon-search") %>
<% end %>
I get a url something like:
http://localhost:3000/en/posts?utf8=%E2%9C%93&search=check+params&ip=127.0.0.1&city=&country=Reserved
My question is:
Can I hide or encrypt the url params ip, city and country?
I can not use POST because I have paginate results:
<a rel="2" href="/en/posts?city=&country=Reserved&ip=127.0.0.1&page=2&search=check+params&utf8=%E2%9C%93">2</a>
<a rel="3" href="/en/posts?city=&country=Reserved&ip=127.0.0.1&page=3&search=check+params&utf8=%E2%9C%93">3/a>
Encrypting URL parameters is pretty pointless. Why don't you want the user to see these values? Sure you COULD encrypt them before adding them to the form, but is that really necessary?
Furthermore, and perhaps more importantly, if these values are based on the request, then there is a good chance you don't need to submit them in the first place. #{request.xxx} is going to be the same on the result page as is on the form page. Is there any good reason to pass these along? By submitting these as GET parameters, you're actually sending redundant information to the server. Ruby/Rails is already going to calculate these values based off of the IP address automatically when the next page is loaded.
The problem here isn't with the form, but rather with the logic you've applied to designing it. I think you may have over-analysed your situation, and need to take a step back and re-think the problem.
I have a single text box form on my home page (/).
Right now the way my Rails routes is set up, when I submit this form, it takes me to /search, but it doesn't publish the query string in my url.
In other words, when I enter in "hello" in that form and press submit, I want to end up at "/search?query=hello". I know that "hello" is in params[:query], but how do I get Rails to publish that query string in the landing page URL after I submit the query?
I read the Rails routes guide but that talks about incoming query strings in the URL, not Rails publishing the URL with the query string visible.
Thanks.
My form tag so far:
<% form_tag(:controller => "search", :action => "search", :method => :get) do %>
<%= text_field_tag 'query' %>
<%= submit_tag "Search"%>
<% end %>
If I do this, I get /search?method=get, but what I would like to see is /search?query=foo.
You just need define a form with get method instead of post
<% form_tag search_url, :method => :get do %>
<%=text_field_tag :search %>
<%= submit_tag %>
<% end %>
Make sure that your form's method (as shown in the HTML page that a client would see before submitting the form) is GET not POST. With POST, the params[:query] is hidden from the user (this is often used for login forms, forms that would submit credit cards or other sensitive information). But if you want the query to show in the URL, you need to use the GET method. Rails itself isn't responsible for this behavior, it's all on the web browser's side.
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.