0

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.

Community
  • 1
  • 1
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • This is not Rails standard, it's HTML/HTTP standard - the issue is that your form uses `get` instead of `post` and that's what a standard URL is for GET requests... – Taryn East Oct 11 '16 at 21:57
  • I know it is not standard. I say that in the question. I have added an edit to show the route I am trying to hit with this form. – rmcsharry Oct 11 '16 at 22:00
  • It cannot be a POST because this has to be a 'permalink' that can be cached. Notice that it is a SEARCH form, so it is not creating anything on the server, just retrieving some search results. – rmcsharry Oct 11 '16 at 22:00
  • There's a difference between a "rails standard" and an "http standard" though and that's what I was pointing out. I recognise why you want to do this... I don't think it's possible, because you're not just messing with rails (which is quite extensible and flexible), you're trying to mess with something fundamental about how the web actually works (which isn't). That's why I felt it important to point out the difference. – Taryn East Oct 11 '16 at 22:14
  • You may plausibly be able to do the URL-based one with interesting routes. Have you read the routing guide and looked at dynamic routes? http://guides.rubyonrails.org/routing.html – Taryn East Oct 11 '16 at 22:15
  • @TarynEast Ok I see what you mean. So I probably need for this to be a POST form, and in the action redirect to a GET that returns the search results. I think that's what I infer from what you are saying. – rmcsharry Oct 11 '16 at 22:25

2 Answers2

2

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.

Community
  • 1
  • 1
gmcnaughton
  • 2,233
  • 1
  • 21
  • 28
  • 1
    Thanks but I think there is a way without using JS, as I just found a related question. I need two separate controller actions and to change the form to a POST. See my new edit. – rmcsharry Oct 11 '16 at 22:36
0

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

rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • 1
    Remember to test with interesting characters (like spaces and slashes) in the search term. Right now if you search for "foo bar", you'll get an error since it will generate an invalid url. Naming the route and using a rails route helper (like `redirect_to my_search_path(params[:search])` should take care of this for you. – gmcnaughton Oct 11 '16 at 23:18
  • @gmcnaughton Thank you so much for that 'gotcha' :) Answer updated to reflect your sage advice – rmcsharry Oct 12 '16 at 10:57