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
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 的一个属性。当您返回代码时,这可能会造成混淆。
问题:为什么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
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 的一个属性。当您返回代码时,这可能会造成混淆。