Passing parameter to form - ruby-on-rails

I have a route like this:
match '/:search/:page', :to => 'search#create'
and in my form:
<%= form_for :search, :url => {:controller => 'search', :action => 'create', :page => 1, :search => ???} do |f| %>
I need to pass something to :search but I want it to be the value that is submitted with the form. What do I do?

There is no straight way to do that as form with url (action) must be rendered before user types anything into search. So you need initial value, but it may not make sense when you don't know what user wants to type in. GET form with parameters would solve it but I suppose you want "nice" search urls.
Generally there are two options:
You can't change URL path by simple form submittion - only params (?x=1&y=2...) may be added. But you can modify whole URL by JavaScript when user types something to search input (onchange) or submits form (onsubmit).
Use another action which will receive standard form input values then redirect it to proper url. E.g. /searchforward?search=Query&page=1 should forward to /Query/1.
routes.rb:
match 'searchforward', :to => 'search#searchforward'
match '/:search/:page, :to => 'search#create', :as => :search
controller:
def searchforward
redirect_to search_path(params[:search],params[:page]
end

If you set a value in form_for, where you have it now, it will be part of the address the form is sent to, therefore you will be able to get it in the controller through params[:search].
You can also make a text field (text area, select box, etc.) for the user to fill the value, as e.g. described in APIDock. You can even have a hidden field, which will not be displayed to the user, but still submitted with the form. In any case, it will be available through params[:search].
Edit Another way of understanding your question is that you want the search parameter in form_for :url to be passed dynamically based on whatever user typed. In this case I can think of three solutions:
Option 1. Submit the form to somewhere independent of :search and redirect from there:
Form: form_for :search, :url=>{:controller=>"search", :action=>"handle"}
SearchController:
def handle
case params[:search] of
when :foo then redirect_to some_path(params[:search], ...)
when :bar then redirect_to other_path(params[:search], ...)
end
end
The disadvantage is that you cannot make a POST-redirect, only GET. The advantage is that the form is processed in one place. Since it is - why not including the whole handling there and skip redirecting? That would be an option I would consider.
Option 2. Use some JavaScript to alter the action parameter of the form HTML element before submission.
Option 3. Use some JavaScript to generate a form based on an earlier selection.
In this scenario there are two forms, only one of which is user-submittable through a button. The first form contains only a drop-down box (text box, radio buttons) and a JavaScript form observer. Based on the value this observer displays the proper form - note that the :search value entered by the user is known at this point when the form is rendered.
Of course, insead of the first form you can use a collection of links if the choice of :search options available to the user is limited. Option 3 is probably not ideal in terms of performance, but should be nice enough to extend, understand and reuse it later.
There might be some other ways to do it, though.

Related

Submitting a form with GET method which doesn't match route

I want to filter results by category and I'd like to use the GET method instead of POST. However, I am doing something wrong that I can't figure out: the form's action does not match the defined route, so it triggers a different method.
Here's the form:
<div>
<%= form_tag '/expenses/search', method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
</div>
Sending this form produces an URL like the following:
http://localhost:3000/expenses/search?utf8=%E2%9C%93&category_name=Alcohol&commit=Search
However the route is defined like this:
resources :expenses
get 'expenses/search/:category_name', to: 'gastos#search_by_category'
This means the URL where the form is submitted isn't the one I'm trying to submit it to. It's matched with the one corresponding to the show method, as you can imagine.
How can I submit the form to the matching URL? What is the usual way to deal with this situation?
You didn't set your route properly as it has unrecognized :category_name segment. Your route should be defined like this:
get 'expenses/search', to: 'gastos#search_by_category`
If your route is nested on expenses I recommend to use block function
resources :expenses do
collection do
match 'search', to: 'gastos#search_by_category`, via: :get
end
end
Is a good practice to use rials routes helper, try to avoid put routes with plain text, in your case will be:
<%= form_tag search_expenses_path, method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
Furthermore, don't confuse 'query params' with 'url params'
http//www.host.com/profile/12?type='json'
In this example '12' is a url param and is expresed with :(nameofparam) in routes files but 'type' is a query param that are not expresed on rails routes.
It's supposed to work like that, since it's client-side.
You see, parameters are sent by the browser, that (in general) has no understanding of how your site routing works inside. Submitting a form, in general, requires an URL (to submit params to) and a set of parameters, which in case with GET typically* gets passed as a query string.
The browser will eventually hit the exact route that is specified in form's URL and supply all the form's parameters in a query string appended to the end in usual format:
...?category=stuff
You simply cannot expect the browser to hit a different route (which query string is not part of) with one form just because it has a different value in one of the <input>s.
* I've never actually seen this done differently, but I didn't find a firm requirement of this either.
Do you really want pretty search links that badly?
You could try to circumvent this by placing a "prettifying redirection" – direct search queries to that action, but do not perform search there: instead use the received parameters to construct a route and redirect your user to it.
def search_redirect
redirect_to whatever_search_path(category: params[:category])
end
That would trigger the route helper to build the pretty adress that conforms to the defined routes.
Too hacky?
Well, you could go with submitting a form through JavaScript and alter the parameters and URL request in any way you want. But this is still hacky and I wouldn't do either. Query string in search requests looks perfectly fine to me.

RoR Apply multiple filtering options while remembering all

I have an events page with two distinct filtering options. One filters by 'period', the other by 'tag'.
The period filter is performed via a GET request and the tag filter uses a form to POST its value.
The defined routes for events:
resources :events
post 'tags/(:tag)', to: 'events#index', as: :tag
get 'events(/period/:period)', to: 'events#index', as: :events_period
My tag filtering uses the tag_path to submit itself:
<%= form_tag tag_path, method: :post, do %>
Both filtering actions are dealt with by the index action in the EventsController.
What I want to do is remember the filtering of period while filtering for tags. In other words, when the url is /period/past and the meh tag is selected, I would like to apply both filtering options.
Could I submit the form to the current url or should I change the route of tag_path to include the period filter?
You could add hidden period field to your tag form and fill it with your current filtering options. After that you'll get you filtering options in params[:period] in controller.
This approach doesn't require to change your routes.
It's been a while, but I used to use the overwrite_params options on url_for. So if you're on a given page you can have a link use the same page with the same parameters as are currently present, and only change the params you want changed. However that seems to have been deprecated in Rails 3. But you can still do it manually like this:
<%= link_to 'Add the meh filter', url_for(params.merge(tag_name: 'meh')) %>

Submit a form to a Rails route with a dynamic segment

I have a route that looks like
match 'solar_systems/:planet_num/:moon_num' => 'solar_system#moon', :as => :moon
I'd like to have a form with a select box for planet number and moon number and have it submit to this route. However I cannot use moon_path because it will have an error if the dynamic parameters are not included in it like this moon_path(4, 1). Is what I want even possible? If so, what do I give to the form tag for the route?
You don't have to use the routing helper methods, and here you can't since at the time of rendering your form you do not know the required parameters. You do, however, know the controller and action, which is really all that's needed for the destination URL. So this should work:
= form_tag('/solar_systems/moon') do
= select_tag(:planet_num, ...
= select_tag(:moon_num, ...
This should render the form tag. To process the request, you will also have to add another route so the right controller action is called:
match 'solar_systems#moon' => 'solar_system#moon', :via => :post
Or, if it makes more sense in the context of your application, you could modify your existing route to make the parameters optional:
match 'solar_systems(/:planet_num(/:moon_num')) => 'solar_system#moon', :as => :moon
See this Rails guide for more details on non-resourceful routes.
If you use this params on controller you need to specified what params is each one, btw in you helper you need to do something like this
moon_path(planet_moon: 4, moon_num: 1)
Cheers!

Ruby on Rails: form and radio button question

I have a form around a list of items. I would like to check a radio button on the list and then, after clicking 'Submit', go to the 'Edit' page of the selected item.
The problem is that if I am writing something like
<%= form_tag edit_item_path %>
but Rails complains that I didn't provided a proper id, which in turn is being set on my radio buttons as the following:
<%= radio_button 'item', 'id', item.id %>
So - how would I send a form with a selected id to a given action?
Doing it the way you describe would not work, since edit_item_path by default RESTful path definitions is a GET request. You are trying to make it a POST request. If you would like to stick to the RESTful way of doing things I would recommend simply looping through your items and provide links to edit, since you are planning to edit them one at a time anyways. Otherwise, you would have to define a new route if you would prefer doing things within the form with radio buttons. If you are, than you would add something like this to your config/routes.rb: (assuming you are using rails 2.3.x)
map.resources :items, :member =>{:edit_radio_form => :post}
Than your form would look like this:
<%= form_tag edit_radio_form_item_path do |form| %>
And it should work, but it not the right way of doing things for several reasons, the most anoying one of which is that you won't get a full URL on your edit page because you got there with a POST request, so if you refresh the page, your item id param will be gone and will produce an error.

Ruby on Rails passing of parameters between views from link_to tag instead of submit_tags (having both on page)

I'm creating in my index page of my ruby on rails program, a list of the most commonly searched for terms in my database and hence each time a user selects a specific category this is written to another database.
What i would like it to create a hyperlink and pass a certain amount of parameters to a form like is usually done with a select_tag but instead with just a hyperlink, i would like to pass a set of hidden fields that i have on the page as well as what the user has selected.
To give you a better idea, basically i have the following structure in my program:
User inputs a search on (index.html.erb), user clicks on submit tag
action, user is taken to search.html.erb page and is displayed a set of refined categories + some fields, submit button,
user is taken to closest.html.erb (which uses parameters from the previous form by invoking the params[:searchSelected] and a few other params. )
I would also like to add this functionality:
Mimick this same operation, but instead of going in the search.html.erb, i would click on an already refined search category on the index.html.erb page (from a link_to , transmit as parameters which link_to the user has chosen + the hidden fields.
i Currently have this code
#stats.each do
|scr|%>
<%= link_to scr.category, :action => 'closest', :id => scr.category%>
I'm not sure if this is relevant, but i currently have the following routes in my routes.rb file
map.resources :stores, :collection => { :search => :get }
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
would anyone please assist me please? this is my first ruby on rails project and i would really like to find a way around this please
I am not sure if this is what you were thinking, but you can add additional parameters to the link_to tag. They are then available in your controller. So:
<%= link_to scr.category, :action => 'closest', :id => scr.category, :other_param => "test" %>
Will be available in your controller.
def closest
params[:other_param] == "test" #this will be true
end
i managed to resolve this by taking the params[:id] and then according to the value either set my own values (instead of the hidden ones in the index.erb which i had set manually anyway) and otherwise, continue as usual had i placed a regular search
View:
<%= link_to obj.ptc_devicename ,"/wiuconfig/hd?idval=#{obj.id.to_s}&val=#{#devicetype}",:value => obj.ptc_devicename,:id =>obj.id %><br/>
Controller:
#Heading= params[:val]
#id=params[:id]
value will be id is 2 and val is #devicetype

Resources