Rails search URI with unwanted parameters? - ruby-on-rails

Background
I am creating a search field in my header. This code in my view:
<% if signed_in? %>
<%=f orm_tag( "/search", method: "get", :class=>"navbar-form navbar-left", :role => "search") do %>
<div class="form-group">
<%=t ext_field_tag :q, nil, :class=>"form-control", :placeholder => 'Domain/IP Search' %>
</div>
<%=b utton_tag "Search", :type=>'submit', :class=> "btn btn-primary" do %>
<span class="glyphicon glyphicon-search"></span>
<% end %>
<% end %>
creates this output:
<form accept-charset="UTF-8" action="/search" class="navbar-form navbar-left" method="get" role="search">
<div style="display:none">
<input name="utf8" type="hidden" value="✓">
</div>
<div class="form-group">
<input class="form-control" id="q" name="q" placeholder="Domain/IP Search" type="text">
</div>
<button class="btn btn-primary" name="button" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
</form>
Here is a picture:
The issue
The problem is when I search, I get this in my url:
/search?utf8=✓&q=test&button=
Ideally, I'd like it to be more like:
/search?q=test
tl;dr:
How do I get rid of the button parameter (and hopefully the utf one as well).
Extra info:
routes.rb
resources :search
search_controller.rb
class SearchController < ApplicationController
def index
#results = params[:q]
puts #results.to_s
end
end
search\index.html.erb
<%=#results.to_s %>
EDIT, answer
Adding this because while the accepted answer helped me get to the solution; it didn't have the exact code for my circumstance. I made these changes:
1) routes:
match '/search', to: 'search#index', via: 'post'
2) form in my header:
<%= form_tag search_path, method: "post", :class => "navbar-form navbar-left", :id=> "SearchForm", :role => "search" do %>
<div class="form-group">
<%= text_field_tag :q, nil, :class => "form-control", :placeholder => 'Domain/IP Search' %>
</div>
<%= button_tag "Search", :type=> 'submit', :class=> "btn btn-primary" do %>
<span class="glyphicon glyphicon-search"></span>
<% end %>
<% end %>

GET
The bottom line, as I wrote in another answer, is that you're using GET:
Essentially, when you submit a GET form, it appends the parameters to your URL, whilst a POST form will append the data to the request body (or somewhere hidden).
The difference is just that the GET request expects a response to be returned immediately, and so you have to pass the parameters in the URL to ensure the server knows how to construct it. The best example being if you use a GET request to load a page.
The POST method is used primarily used for forms, where a response is not expected immediately; thus allowing you to keep the params hidden in the request.
Fix
We've actually created a basic search feature here (the actual search doesn't work for some reason, but the live search does)
The way we did it was as follows:
match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]
This will firstly allow you to access the search action by typing domain.com/search/your-query-here
In terms of submitting via a form, you'll be able to use JQuery to amend the URL with the input from the text field:
#app/views/elements/_nav.html.erb
<%= form_tag search_path, :method => :post, :id => "SearchForm" do %>
<%= text_field_tag :search, params[:search], placeholder: 'Search your favourite products or brands', :autocomplete => :off, :id => 'SearchSearch' %>
<%= image_submit_tag('nav_bar/search.png', title: 'Search', class: 'search_submit', data: { "placement" => "bottom" }) %>
<% end %>
#app/assets/javascripts/application.js
//Search Submit
$(document).ready(function() {
$('#SearchForm').submit(function(e) {
e.preventDefault();
if( $('#SearchSearch').val().length > 0 ) {
var search_params = '/' + $('#SearchSearch').val().toLowerCase();
}else{
var search_params = ''
}
window.location.href = $(this).attr('action') + search_params
});
});

If you are not doing with the Utf8 parameter but, Rails is & but its needed. It's to correct some issues in IE's parameter encoding, This parameter was added to forms in order to force Internet Explorer 5, 6, 7 and 8 to encode its parameters as unicode.Its fixes encodeing issue of IE.
Please refer following link:
What is the _snowman param in Ruby on Rails 3 forms for?

This parameter is a feature of rails.
It was previously the snowman.
It helps IE to really use utf-8.
Avoid using form_tag and it works:
<form action="<%= search_path %>" method="get" >
<%= text_field_tag 'query' %>
<%= submit_tag "Search", :name => nil%>
</form>
Now style your form as you want

Related

Undefined method when trying to pass through id

I'm trying to pass a project ID from its show page to an employee_projects form where I can display the projects name. The error I'm getting is
undefined local variable or method `project_id' for #<EmployeeProjectsController:0xb8bdd58>.
employee_project controller:
# GET /employee_projects/new
def new
puts params[project_id]
#project = Project.find(params[:project_id])
session[:project_id] = #project.id
#employee_project = EmployeeProject.new
end
employee_projects form
Assign worker for this project <%= project.projectName%><br>
<div class="field">
<%= f.label :employee_id %><br>
<%= f.collection_select :employee_id, Employee.all, :id, :empLastName, :prompt => "Select worker" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Projects show
<%= button_to "Assign!", new_employee_project_path(project_id: #project.id) , class: "btn btn-primary", :method => :get %>
Does anyone have any ideas on how to fix this?
In your controller try changing puts params[project_id] to puts params[:project_id].
params is a Hash so you must refer to its keys with symbols, that is :project_id. project_id is just a variable that has no value assigned to it, hence the error undefined local variable or method 'project_id' for #.
UPDATE ("Couldn't find Project with 'id'=" fix)
The button in projects' show view is not sending the parameter project_id even though you are passing it to the new_employee_project_path helper (check your url string and you will see it ending at ? with no parameters). To fix it, i recommend using a regular form instead of button_to helper.
So, instead of this line:
<%= button_to "Assign!", new_employee_project_path(project_id: #project.id) , class: "btn btn-primary", :method => :get %>
Try using this form:
<form action="<%= new_employee_project_path %>" method="get">
<input type="hidden" name="project_id" value="<%= #project.id %>">
<input type="submit" value="Assign!" class="btn btn-primary">
</form>

Rails 4.2 use form_tag to create search but without using query string params

EDIT 2
Related question here.
EDIT
This is the route I need to submit to:
get '/s/:term', controller: :products, action: :search, as: :search_products
I have a search form like this:
<%= form_tag(search_products_path, :method => "get", id: "search-form", name: "f1", enforce_utf8: false) do %>
<div class="input-group">
<%= text_field_tag :search, params[:search], placeholder: "Search products", class: "form-control", name: "search" %>
<div class="input-group-btn">
<button class="btn btn-secondary">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
</div>
<% end %>
But this creates the url like this:
domain/s?search=[user input]
I need the URL to be like this instead:
domain/s/[user_input]
Yes I do know this is not following Rails convention. I couldn't care less at this point, I just need to figure it out.
Thanks.
There's no way to do this using just form_tag, since the url that the form submits to needs to be dynamic. But it can be done using javascript:
$("#search-form").submit(function(evt) {
var term = $("#search-form input[name='search']").val();
$(this).attr('action', '/s/' + encodeURIComponent(term));
});
This will result in the form submitting to: domain/s/[user input]?search=[user input]
You could further prevent the ?search= parameter from being included in the url by omitting the name attribute from the field (see https://stackoverflow.com/a/3008071/157943), though then you'd need to give it an id or some other way for the javascript snippet above to locate it.
Thanks to the comments from #TarynEast and the other question linked in my second edit, I realised I was very confused - so thank you Taryn!
This has to be done in 2 separate actions/routes, like this:
post '/s', controller: :products, action: :search, as: :search_products
get '/s/:search', controller: :products, action: :index, as: search_results_path
Whatever the user inputs is then posted by the form to that search action.
Here is the form:
<%= form_tag(search_products_path, :method => "post", id: "search-form", name: "f1", enforce_utf8: false) do %>
<div class="input-group">
<%= text_field_tag :search, params[:search], placeholder: "Search products", class: "form-control", name: "search" %>
<div class="input-group-btn">
<button class="btn btn-secondary">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
</div>
<% end %>
The products#search action simply does a redirect:
def search
# ORIGINALLY: redirect_to "/s/#{params[:search]}"
redirect_to search_results_path(params[:search])
end
Then we can extract the :search param and use it to search the model, like so:
def index
if params[:search] && !params[:search].blank?
#products = Product.search params[:search]
...
etc

Rails form_for sending params to controller action and not model

In the controller review_queue I have a custom action that posts a result to a target URL, I want to build a form for this action. I am not going to save any of the fields to the DB I am just going to pass them in the params to the post_review action.
def post_review
RestClient::Request.execute(:method => :post,
:url => Rails.application.secrets['target_url'],
:content_type => :json,
:payload => #result_params.merge!(params[:reasons]).to_json,
:headers => HEADERS)
end
In the view I have a form that will be filled out and on submit it should send up the reasons when the form is submited, I am setting the review_queue_id and the status in the form, since these are static, but the reasons should come from the textarea
<%= form_for(:review_queue, url: { action: 'post_review', :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= f.text_area(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= f.submit 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
error message:
NoMethodError - undefined method `reasons' for #<ReviewQueueApplication:0x007fa7ff7832d8>:
It seems as if rails is assuming the MVC architecture here, and assuming I want to pass the reasons to the review_queue model. there is no reasons column so it's dropping a no method error. Is there a way of specifying that the form is 'temporary' and only getting as far as the controller?
This seems like it should be a simple thing but there is some rails magic happening here.
NoMethodError - undefined method `reasons' for
ReviewQueueApplication:0x007fa7ff7832d8
form_for assumes that you are creating a form for a model object and expects the fields to be present in that specific model's table(in a normal situation).
You should be going with form_tag
<%= form_tag post_review_path, method: :get, :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= text_area_tag(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= submit_tag 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
And in the controller access it like params[:reasons]. Also if you noticed, I've added method: :get to the form_tag as you don't want to save the info to DB
The rails helper form_for is used for forms for rails resources. You want to use the form_tag helper. Search for form_for and form_tag here for more information on these 2 methods.

Why form_tag is generating form with wrong url (No route matches [POST] "/assets")

I looked at some posts about this question, but I can't get how to solve this.
I have index page on which I have form which I will use to take them from params hash from it.
Here is form:
<%= form_tag(:action => '/show', :method => "get") do %>
<%= datepicker_input "report","start_date", :dateFormat => "dd/mm/yy" %>
<%= datepicker_input "report", "end_date", :dateFormat => "dd/mm/yy"%>
<%= submit_tag "Run Report", :class => "btn super", :id => "btn "%>
< %end %>
and input's names:
<input id="report_start_date" name="report[start_date]" size="30" type="text" class="hasDatepicker">
<input id="report_end_date" name="report[end_date]" size="30" type="text" class="hasDatepicker">
but it is generating URL like this:
action="/assets?action=%2Fshow&controller=financial_reports&method=get"
Also, I need to pass params values into index controller, like this :
def index
start_date = params[:start_date]
end_date = params[:end_date]
#financial_reports = current_user.financial_reports#.where(:created_at => the_start.to_date..the_end.to_date)
end
but it of course giving me error 'undefined method for nilClass'.
How can I solve this problem ?
Is the space between < and & in your last line a typo in SO? Otherwise Ruby might mess things up because the form tag is ended at complete another place than you think it is...

Generate hidden form field data with rails button_to helper?

Currently, i use the following code for passing params[:id] to line_items create
<%= button_to 'Add to Cart', { controller: 'line_items', action: 'create', id: brick }, class: 'green radius nice button', method: :post, remote: true %>
However, it will append the id param on url query which i didn't suppose button_to to do. What i want is passing the id param via hidden the form field. Can i do that in button_to or any workaround for this issue?
Starting with Rails 4.1.0, button_to has now the additional options :params which can receive a hash that will be transformed into hidden fields. For example:
button_to 'Send Invitation', invitation_path(user), params: {'user[email]' => user.email}
Will give :
<form action="/users/invitation" class="button_to" method="post">
<div>
<input type="submit" value="Resend">
<input name="user[email]" type="hidden" value="user#yahoo.com">
</div>
</form>
I have done something similar in a module of my project:
First, I added a form with a hidden field:
<%= form_tag({:action => 'my_action'}, :id=>"item_form", :method => :post, :remote=>true) do%>
<%= hidden_field_tag :item_id, 0%>
<% end %>
all mi items on the list will have a check_box_tag wich contains the item id:
<%= check_box_tag "item_ids", item.id, false,:id => item.id, :class => "my_fancy_class"%>
when an item is picked just catch the event, replace the value on the hidden_field and trigger the form:
function( event, ui ) {
$("#item_id").attr('value',ui.selected.id);
$('form#item_form').submit();
}
if you want to render stuff just add a action.js.erb file to your controller view folder, but thats another thing.

Resources