我有一个应用程序,其中有一个带有姓名字段的医生表。用户可以在其中放置他们想要的任何版本的名称。在索引视图中显示记录之前,我尝试根据姓氏(字符串中的最后一个单词)对记录进行排序。
我想出了一个可以在控制台中运行的查询,但在控制器中运行它时出现错误。
查询如下:
current_user.doctors.select("doctors.*, split_part(doctors.name, ' ', -1) AS lastname").order('lastname ASC')
我的表迁移:
class CreateDoctors < ActiveRecord::Migration[7.1]
def change
create_table :doctors do |t|
t.string :name
t.string :field
t.string :address
t.string :phone
t.string :fax
t.string :website
t.string :portal
t.binary :active, default: true
t.string :group
t.timestamps
end
end
end
我的控制器代码:
def index
@doctors =
current_user.doctors.select("doctors.*, split_part(doctors.name, ' ', -1) AS lastname").order('lastname ASC')
end
我的查看代码:
<%= turbo_frame_tag Doctor.new %>
<%= turbo_frame_tag "doctors" do %>
<% @doctors.each do |doctor| %>
<%= render 'doctor_index', doctor: doctor %>
<% end %>
<% end %>
我得到的错误如下:
17:16:53 web.1 | Started GET "/doctors" for ::1 at 2024-03-16 17:16:53 -0600
17:16:53 web.1 | ActiveRecord::SchemaMigration Load (1.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
17:16:53 web.1 | Processing by DoctorsController#index as HTML
17:16:53 web.1 | User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]]
17:16:53 web.1 | Rendering layout layouts/application.html.erb
17:16:53 web.1 | Rendering doctors/index.html.erb within layouts/application
17:16:53 web.1 | Rendered shared/_nav-tabs.erb (Duration: 1.2ms | Allocations: 482)
17:16:53 web.1 | Doctor Count (21.8ms) SELECT COUNT(doctors.*, split_part(doctors.name, ' ', -1) AS lastname) FROM "doctors" WHERE "doctors"."user_id" = $1 [["user_id", 2]]
17:16:53 web.1 | ↳ app/views/doctors/index.html.erb:12
17:16:53 web.1 | Rendered doctors/index.html.erb within layouts/application (Duration: 83.8ms | Allocations: 17358)
17:16:53 web.1 | Rendered layout layouts/application.html.erb (Duration: 84.2ms | Allocations: 17477)
17:16:53 web.1 | Completed 500 Internal Server Error in 254ms (ActiveRecord: 42.9ms | Allocations: 54020)
17:16:53 web.1 |
17:16:53 web.1 |
17:16:53 web.1 |
17:16:53 web.1 | ActionView::Template::Error (PG::SyntaxError: ERROR: syntax error at or near "AS"
17:16:53 web.1 | LINE 1: ...OUNT(doctors.*, split_part(doctors.name, ' ', -1) AS lastnam...
17:16:53 web.1 | ^
17:16:53 web.1 | ):
17:16:53 web.1 | 9: </div>
17:16:53 web.1 | 10: <%= turbo_frame_tag Doctor.new %>
17:16:53 web.1 | 11: <%= turbo_frame_tag "doctors" do %>
17:16:53 web.1 | 12: <% if @doctors.count != 0 %>
17:16:53 web.1 | 13: <% @doctors.each do |doctor| %>
17:16:53 web.1 | 14: <%= render 'doctor_index', doctor: doctor %>
17:16:53 web.1 | 15: <% end %>
17:16:53 web.1 |
在控制台中运行它会产生我正在寻找的结果,这是按姓氏排序的医生记录列表。
我确信这是从 Rails 查询到 psql 查询的转换问题,但我不知道如何重写它,以便它按照我想要的方式工作。我很困惑为什么它在控制台中工作但在控制器中不起作用。
声明为:
SELECT COUNT(doctors.*, split_part(doctors.name, ' ', -1) AS lastname)
计数从何而来?我们来看看错误信息。
17:16:53 web.1 | 9: </div>
17:16:53 web.1 | 10: <%= turbo_frame_tag Doctor.new %>
17:16:53 web.1 | 11: <%= turbo_frame_tag "doctors" do %>
17:16:53 web.1 | 12: <% if @doctors.count != 0 %>
17:16:53 web.1 | 13: <% @doctors.each do |doctor| %>
17:16:53 web.1 | 14: <%= render 'doctor_index', doctor: doctor %>
17:16:53 web.1 | 15: <% end %>
来自
<% if @doctors.count != 0 %>
。
如果您只想按姓氏排序,则可以直接使用
order
并保留所选列。
current_user.doctors.order("split_part(doctors.name, ' ', -1) asc")
如果您经常这样做,并且有很多医生,您将需要进行索引查询。您可以在该特定表达式上添加 索引...
create index doctor_lastname_idx on doctors(split_part(name, ' ', -1))
或者您可以将其添加为生成列。您可以将姓氏列添加到医生表中,并在 before_save callback...
中执行此操作class Doctor < ApplicationRecord
...
before_save :set_lastname
private def set_lastname
self[:lastname] = name.rpartition(/\s+/).last
end
end
或者您可以直接在数据库中使用真正的虚拟列来完成。
change_table :users do |t|
t.virtual :lastname, type: :string, as: 'split_part(doctors.name, ' ', -1)', stored: true
t.index(:lastname)
end