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.
Related
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.
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.
Here's my code for a form that contains a drop down list -
<div class="field">
<%= f.label :type, "Select profile type"%>
<%=
f.select :type, Profile::TYPES,
:prompt => "Select a profile type"
%>
</div>
The drop down menu looks fine. But, how would I check which option is selected? I want to route to a different view based on this selection.
Thanks in advance!
The logic of routing to a different view should occur in your controller. When the user submits this form, check the value of the params, and perform your logic to route to a view:
class ExampleController
def routing
case params[:example][:type]
when 'foo'
redirect_to foo_path
when 'bar'
redirect_to bar_path
end
end
You can create a custom action name, since this routing isn't one of the CRUD operations. You will need to place this route into the config/routes.rb file if it is a custom name.
Optionally, you can bind to the select's onChange event, as mentioned by others to auto-submit the form when the user changes the value. This would still send the data to the controller and perform a redirect. The advantage to this approach is that you can keep your route information out of Javascript, and in the Rail's controller.
More on Rails routing can be found here: http://guides.rubyonrails.org/routing.html
More on Javascript binding to onChange can be found here: http://www.w3schools.com/jsref/event_onchange.asp
You should be able to use jQuery or any other popular Javascript framework to achieve this -- either attach an onChange listener or set the value somewhere and check it. Events, yay, etc.
I am new to Rails and don't quite understand what I'm supposed to do. Let's say, for example, I want a textbox containing a string to be passed into another controller (another page?) when the user clicks a button. How would I go about doing that?
Functions of controllers are pages, correct? Can a function take parameters just like a normal method? (E.g. sum(x,y))
For complete information, check out Rails Form helpers. Basically, you give the form_tag method a path which points to the controller and the action that you want to handle the form submission. For example,
<%= form_tag(search_path, :method => "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
Here, the action and controller that search_path points to (defined in your routes) will receive the form submission and the value from the text field.
Your action in the controller IS a function, but it will not receive the value from the form submission as a parameter to the function. Instead, you will access it through the params hash. In the example above, you can access the value from the text field as
params[:q]
What are you doing with the string? Storing it? Using it as a parameter on another page?
I suggest you take a look at the Getting Started Guide, go through it, and pay particular attention to the What is Rails? section, where it explains MVC architecture and REST (Representational State Transfer.)
There are dozens of other Rails tutuorials out there, I'm sure if you searched this site you'd find many questions like this one:
https://stackoverflow.com/questions/2794297/how-to-learn-ruby-on-rails-as-a-complete-programming-beginner
Functions of controllers are pages, correct? Can a function take parameters just like a normal method?
Functions of controllers are pages if that's the route you've set up in your routes.rb configuration file. I suggest you run through some tutorials to understand what Rails is for and how it works.
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