https://select2.org/getting-started/basic-usage
I want to search for a Post title like the first example in the link above.
Code:
<!-- search -->
<div class="card my-auto">
<%= form_with url: posts_path, method: :get, local: :true do |f| %>
<div class="card-body">
<p>Search for a Post title.</p>
<%= f.collection_select(:post_id, Post.all, :id, :title, {include_blank: 'Post titles'}, {class:'selectbooktitle form-control'}) %>
<hr>
<div class="input-group">
<span class="input-group-btn">
<%= f.submit 'Search', class: 'btn btn-outline-success'%>
</span>
<% end %>
</div>
</div>
</div>
This is the Request from my server when clicking on Submit.
Started GET "/posts?utf8=%E2%9C%93&post_id=16&commit=Search" for 127.0.0.1 at 2018-05-09 14:18:51 +0200
Processing by PostsController#index as HTML
Parameters: {"utf8"=>"✓", "post_id"=>"16", "commit"=>"Search"}
Rendering posts/index.html.erb within layouts/application
Post Load (0.3ms) SELECT "posts".* FROM "posts"
Post Load (0.3ms) SELECT "posts".* FROM "posts" ORDER BY created_at DESC
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 4], ["LIMIT", 1]]
Rendered posts/index.html.erb within layouts/application (10.2ms)
Category Load (0.3ms) SELECT "categories".* FROM "categories"
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]]
Rendered layouts/_navbar.html.erb (4.5ms)
Rendered layouts/_alerts.html.erb (0.4ms)
Rendered layouts/_footer.html.erb (0.6ms)
Completed 200 OK in 59ms (Views: 55.0ms | ActiveRecord: 1.9ms)
Leads to this URL:
http://localhost:3000/posts?utf8=%E2%9C%93&post_id=20&commit=Search
it should lead to the following URL:
http://localhost:3000/posts/20
What am I doing wrong?
Thank you in advance for any help!
The Rails framework is not wrong for sending you to that URL, since you set the form_with :url
option to posts_path
. This is equal to /posts
.
What you are trying to do is change the form action based on the select content. For this you'll need JavaScript to change the form action on the fly.
Here is a simplified example:
app/views/some_directory/some_file.html.erb
<%= form_with url: posts_path, method: :get, local: true do |form| %>
<% options = {include_blank: 'Post titles'} %>
<% html_options = {
class: 'selectbooktitle form-control',
'data-change-form-action-with-value': true,
} %>
<%= form.collection_select :post_path, Post.all, method(:post_path), :title, options, html_options %>
<%= form.submit 'Search', class: 'btn btn-outline-success'%>
<% end %>
app/assets/javascripts/some_file.coffee
initChangeFormActionWithValue = (selectElement) ->
selectElement = $(selectElement)
closestAncestorForm = selectElement.closest('form')
selectElement.on 'change', ->
closestAncestorForm.attr 'action', selectElement.val()
$(document).on 'turbolinks:load', ->
$('select[data-change-form-action-with-value="true"]')
.each -> initChangeFormActionWithValue(this)
Now when changing the select value the form is updated with the value of the selected option (which contains the post path). And when you submit your request you'll request GET /posts/:id
.
Note: This is a simplified solution. Which requests
GET /posts/:id
of the selected post. However the values of the form are also submitted. You can leave them unhandled, but should at least know that their there. So you are not surprised when you see the post_path or submit params in the show.Furthermore if you don't change the select at all when pressing submit you currently just request
GET /posts
. And if you change to select value to a post and back to'Post titles'
(the blank value), the action is cleared. Which means you get the current URL.
Alternatively you can go with your current solution. Than in your PostsController#index redirect to PostsController#show if params[:post_id]
is present.
class PostsController < ApplicationController
def index
return redirect_to post_path(params[:post_id]) if params[:post_id]
# other index code
end
end