Rails 查询在控制台中工作,但不在控制器中工作

问题描述 投票:0回答:1

我有一个应用程序,其中有一个带有姓名字段的医生表。用户可以在其中放置他们想要的任何版本的名称。在索引视图中显示记录之前,我尝试根据姓氏(字符串中的最后一个单词)对记录进行排序。

我想出了一个可以在控制台中运行的查询,但在控制器中运行它时出现错误。

查询如下:

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 查询的转换问题,但我不知道如何重写它,以便它按照我想要的方式工作。我很困惑为什么它在控制台中工作但在控制器中不起作用。

ruby postgresql rails-activerecord ruby-on-rails-7
1个回答
0
投票

声明为:

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
© www.soinside.com 2019 - 2024. All rights reserved.