Rails find_by_sql 没有 return 从关联的 tables/models 请求列

Rails find_by_sql does not return requested columns from associated tables/models

问题:为什么p.name没有返回?

sql = "
SELECT reports.id, reports.address, p.name 
FROM reports
JOIN places_reports pr ON reports.id = pr.report_id
JOIN places p ON pr.place_id = p.id
WHERE reports.id = 14
"

Report.find_by_sql(sql)

Returns:

#<Report id: 14, address: "New Gisborne, vic, Australia">, #<Report id: 14, address: "New Gisborne, vic, Australia">]

文档有点模糊,但似乎暗示它应该作为报表的属性返回。

https://apidock.com/rails/ActiveRecord/Base/find_by_sql/class

谢谢AJFaraday

sql = "
SELECT reports.id, reports.address, p.name 
FROM reports
JOIN places_reports pr ON reports.id = pr.report_id
JOIN places p ON pr.place_id = p.id
WHERE reports.id = 14
"

ActiveRecord::Base.connection.select_all(sql)

您看到的 return 值:

#<Report id: 14, address: "New Gisborne, vic, Australia">, #<Report id: 14, address: "New Gisborne, vic, Australia">]

#inspect 输出,它只包含 Report 知道的列。来自 SQL 的额外值仍然存在并且具有访问器方法,因此您可以这样说:

sql = %q(
  SELECT reports.id, reports.address, p.name 
  FROM reports
  JOIN places_reports pr ON reports.id = pr.report_id
  JOIN places p ON pr.place_id = p.id
  WHERE reports.id = 14
)
Report.find_by_sql(sql).each { |r| puts r.name }

它会起作用的。您还可以向 SQL 添加别名以获取 "better" 方法名称:

sql = %q(
  SELECT reports.id, reports.address, p.name as place_name
  FROM reports
  JOIN places_reports pr ON reports.id = pr.report_id
  JOIN places p ON pr.place_id = p.id
  WHERE reports.id = 14
)
Report.find_by_sql(sql).each { |r| puts r.place_name }

我匆忙发表评论,当时我不在计算机附近,并且错过了您可以访问不属于记录的属性的记录 select 通过 [=36] 查找=].

以下是其他选项:

如果您不想在模型中定义功能,您可以通过返回数据库连接并调用 select_all 来获取原始数据,其中 returns 是一个哈希数组。

ActiveRecord::Base.connection.select_all(sql)
# [{'id': 1, 'address': '123 fake street', 'name': 'harry'}]

您也可以在 SQL 本身中随意命名这些属性:

sql = <<-SQL
  SELECT reports.id report_id, reports.address, p.name place_name
  FROM reports
  JOIN places_reports pr ON reports.id = pr.report_id
  JOIN places p ON pr.place_id = p.id
  WHERE reports.id = 14
SQL

或者,如果您想要模型(或两个模型)的功能,您可以将它们包含在您的 select 中。例如

report = Report
  .includes(report_places: :places)
  .where(report_id: 14)
  .first
# Runs 3 SQL statements up-front (no matter how many records are found)
report.places
# No SQL staements run, array of Place model instances returned

正如@mu-is-too-short 指出的那样,您可以只获取 Report 实例的属性,但有几个原因我不会选择这样做。

  • 将返回多个具有相同 ID 但名称不同的 Report 实例。
  • 它给人一种错误的印象,即 name 是 Report 的一个属性。当您返回代码时,这可能会造成混淆。