Phoenix图书应用中搜索与排序功能整合实现技术求助
Hey there! Let's get that sorting feature working seamlessly with your existing search functionality. I'll break this down into simple, actionable steps to integrate everything properly.
1. Update Your Sort Form to Preserve Search Queries
First, we need to make sure that when a user searches for a book and then sorts the results, the search term isn't lost. We'll add a hidden input to carry the current search query, and set the select's default value to the active sorting option:
<%= f = form_for @conn, book_path(@conn, :index), [method: :get, as: "order_and_filter"], fn f-> %> <%# Carry over the current search query %> <%= hidden_input f, :query, value: get_in(@conn.params, ["order_and_filter", "query"]) || get_in(@conn.params, ["query"]) %> <% options = ["Order by": "", "Title": "title_asc", "Title (Desc)": "title_desc", "Price": "price_asc", "Price (Desc)": "price_desc"] %> <%# Set default selected value to current sorting %> <%= select f, :order_by, options, class: "tag-select tag-select-sm", selected: get_in(@conn.params, ["order_and_filter", "order_by"]) %> <%= submit "Sort" %> <% end %>
2. Add Sorting Logic to Your Book Schema
Next, we'll add a sort/2 function to your Book schema to handle translating the user's selection into Ecto query order clauses. We'll also tweak the existing search/2 function to remove the hardcoded similarity sort (we'll handle that conditionally later):
defmodule Bookstore.Books.Book do use Ecto.Schema import Ecto.Query schema "books" do field(:description, :string) field(:image_url, BookstoreWeb.Uploaders.ImageUploader.Type) field(:isbn, :string) field(:original_price, :float) field(:title, :string) field(:slug, :string) field(:year_published, :integer) field(:quantity, :integer) # Your other associations/fields here end def search(query, nil), do: query def search(query, ""), do: query def search(query, search_term) do wildcard_search = "%#{search_term}%" from(b in query, join: a in assoc(b, :author), where: fragment("? % ?", b.title, ^wildcard_search), or_where: ilike(b.description, ^wildcard_search), or_where: ilike(a.last_name, ^wildcard_search), or_where: ilike(a.first_name, ^wildcard_search) ) end # New sorting function def sort(query, nil), do: query def sort(query, ""), do: query def sort(query, "title_asc"), do: from b in query, order_by: [asc: b.title] def sort(query, "title_desc"), do: from b in query, order_by: [desc: b.title] def sort(query, "price_asc"), do: from b in query, order_by: [asc: b.original_price] def sort(query, "price_desc"), do: from b in query, order_by: [desc: b.original_price] def sort(query, _invalid), do: query # Fallback for invalid values # Helper for similarity sorting when no user-selected sort is present def with_similarity_sort(query, nil), do: query def with_similarity_sort(query, ""), do: query def with_similarity_sort(query, search_term) do from(b in query, order_by: fragment("similarity(?, ?) DESC", b.title, ^search_term)) end end
3. Update Inventory.ex to Handle Both Search and Sort
Now we'll modify the list_books/1 function to coordinate search, similarity sorting (when needed), and user-selected sorting:
defmodule Bookstore.Inventory do import Ecto.Query, warn: false alias Bookstore.Repo alias Bookstore.Books.Book def list_books(params) do # Extract parameters from the sort form (or fallback to old search params) order_and_filter = Map.get(params, "order_and_filter", %{}) search_term = Map.get(order_and_filter, "query") || Map.get(params, "query") order_by = Map.get(order_and_filter, "order_by") # Build the query step by step query = Book |> Book.search(search_term) # Apply sorting: user's selection takes priority, else similarity sort if searching query = cond do order_by -> Book.sort(query, order_by) search_term -> Book.with_similarity_sort(query, search_term) true -> Book.sort(query, "title_asc") # Default sort when no search/sort selected end query |> preload([:category, :author]) |> Repo.all() end end
How This Works
- No Search + No Sort: Books are sorted by title ascending (you can change this default if you want)
- No Search + Sort: Full list of books is sorted by the user's selected field (title/price, asc/desc)
- Search + No Sort: Search results are sorted by similarity to the search term (like your original behavior)
- Search + Sort: Search results are sorted by the user's selected field, overriding the similarity sort
This setup ensures both features work together smoothly without conflicts.
内容的提问来源于stack exchange,提问作者Kapeusz

