You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 16:52:51