您可以根据 Rails 中的 JSONB 列建立关联吗?
Can you have an association based on a JSONB column in Rails?
我有一个 Rails 应用程序(rails v6.0.3,ruby 2.7.1)正在使用 Noticed gem 发送通知。我有以下模型配置:
class Vendor < ApplicationRecord
has_noticed_notifications
end
has_noticed_notifications
,如其 README 中所述,是“用于关联和销毁通知记录的助手 where(params: {param_name.to_sym => self})
”
所以当我像这样创建通知时...
VendorAddedNotification.with(
vendor: vendor,
data_source: "user",
).deliver(some_user) # => Notification inserted!
我希望能够使用 Noticed 方法找到引用供应商的通知,如下所示:
vendor = Vendor.find ...
vendor.notifications_as_vendor # => Expected: [ Notification#123 ]
但是,输入始终是空数组 (Actual => []
)
我查看了 their source code,看起来 notifications_as_vendor
是以下查询:
Notification.where(params: { :vendor => self }) # where self = an instance of the Vendor model
但是,这似乎不起作用,我不确定它是否应该这样做。我尝试了 运行 一个更简单的查询,看看它是否有效...
Notification.where(params: { :data_source => "user" })
但这也没有用。但是,当我 运行 使用不同签名的相同查询时,它确实:
Notification.where("params->>'data_source' = ?", "user")
所以我的问题是——这是 Notified 的错误,还是我的配置中遗漏了什么?我为此使用 PSQL,这是相关的架构:
...
create_table "notifications", force: :cascade do |t|
t.string "recipient_type", null: false
t.bigint "recipient_id", null: false
t.string "type", null: false
t.jsonb "params"
t.datetime "read_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["read_at"], name: "index_notifications_on_read_at"
t.index ["recipient_type", "recipient_id"], name: "index_notifications_on_recipient_type_and_recipient_id"
end
...
以下是相关模型:
class VendorAddedNotification < Noticed::Base
deliver_by :database
param :vendor
param :data_source
end
class Notification < ApplicationRecord
include Noticed::Model
belongs_to :recipient, polymorphic: true
end
提前致谢!
我找到了它不起作用的原因,这似乎是 Notified 的问题。
简单来说SQL我运行:
# PLAIN SQL
select "params" from "notifications" limit 1
哪个returns通知的参数(返回通知的id=77)
# PLAIN SQL Result
"{""added_by"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceMember/269""}, ""data_source"": ""user"", ""_aj_symbol_keys"": [""workspace_vendor"", ""data_source"", ""added_by""], ""workspace_vendor"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceVendor/296""}}"
现在 Rails 当我
vendor = Notification.find(77).params[:vendor]
vendor.notifications_as_vendor.to_sql
结果是...
"SELECT \"notifications\".* FROM \"notifications\" WHERE \"notifications\".\"params\" = '{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}'"
...从该查询中提取的参数是:
'{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}'
所以...在数据库中,序列化的参数是A,但是Rails是搜索B:
# A: `params` In the database
"{""added_by"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceMember/269""}, ""data_source"": ""user"", ""_aj_symbol_keys"": [""vendor"", ""data_source"", ""added_by""], ""vendor"": {""_aj_globalid"": ""gid://stack-shine/Vendor/296""}}"
# B: `params` Searched with by Rails
"{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}"
显然这个查询无法工作,因为数据库中的参数不是 Rails 正在搜索的参数。
数据库中的通知在“供应商”(“data_source”和“added_by”)之上有额外的参数,Vendor
.这就是为什么 returns 什么都没有吗?
现在,我将通过将 vendor_id 存储在参数中并执行类似 Notification.where("params >> vendor_id = ?", 123)
的操作来简单地自己查找通知
我有一个 Rails 应用程序(rails v6.0.3,ruby 2.7.1)正在使用 Noticed gem 发送通知。我有以下模型配置:
class Vendor < ApplicationRecord
has_noticed_notifications
end
has_noticed_notifications
,如其 README 中所述,是“用于关联和销毁通知记录的助手 where(params: {param_name.to_sym => self})
”
所以当我像这样创建通知时...
VendorAddedNotification.with(
vendor: vendor,
data_source: "user",
).deliver(some_user) # => Notification inserted!
我希望能够使用 Noticed 方法找到引用供应商的通知,如下所示:
vendor = Vendor.find ...
vendor.notifications_as_vendor # => Expected: [ Notification#123 ]
但是,输入始终是空数组 (Actual => []
)
我查看了 their source code,看起来 notifications_as_vendor
是以下查询:
Notification.where(params: { :vendor => self }) # where self = an instance of the Vendor model
但是,这似乎不起作用,我不确定它是否应该这样做。我尝试了 运行 一个更简单的查询,看看它是否有效...
Notification.where(params: { :data_source => "user" })
但这也没有用。但是,当我 运行 使用不同签名的相同查询时,它确实:
Notification.where("params->>'data_source' = ?", "user")
所以我的问题是——这是 Notified 的错误,还是我的配置中遗漏了什么?我为此使用 PSQL,这是相关的架构:
...
create_table "notifications", force: :cascade do |t|
t.string "recipient_type", null: false
t.bigint "recipient_id", null: false
t.string "type", null: false
t.jsonb "params"
t.datetime "read_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["read_at"], name: "index_notifications_on_read_at"
t.index ["recipient_type", "recipient_id"], name: "index_notifications_on_recipient_type_and_recipient_id"
end
...
以下是相关模型:
class VendorAddedNotification < Noticed::Base
deliver_by :database
param :vendor
param :data_source
end
class Notification < ApplicationRecord
include Noticed::Model
belongs_to :recipient, polymorphic: true
end
提前致谢!
我找到了它不起作用的原因,这似乎是 Notified 的问题。
简单来说SQL我运行:
# PLAIN SQL
select "params" from "notifications" limit 1
哪个returns通知的参数(返回通知的id=77)
# PLAIN SQL Result
"{""added_by"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceMember/269""}, ""data_source"": ""user"", ""_aj_symbol_keys"": [""workspace_vendor"", ""data_source"", ""added_by""], ""workspace_vendor"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceVendor/296""}}"
现在 Rails 当我
vendor = Notification.find(77).params[:vendor]
vendor.notifications_as_vendor.to_sql
结果是...
"SELECT \"notifications\".* FROM \"notifications\" WHERE \"notifications\".\"params\" = '{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}'"
...从该查询中提取的参数是:
'{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}'
所以...在数据库中,序列化的参数是A,但是Rails是搜索B:
# A: `params` In the database
"{""added_by"": {""_aj_globalid"": ""gid://stack-shine/WorkspaceMember/269""}, ""data_source"": ""user"", ""_aj_symbol_keys"": [""vendor"", ""data_source"", ""added_by""], ""vendor"": {""_aj_globalid"": ""gid://stack-shine/Vendor/296""}}"
# B: `params` Searched with by Rails
"{\"vendor\":{\"_aj_globalid\":\"gid://stack-shine/Vendor/296\"},\"_aj_symbol_keys\":[\"vendor\"]}"
显然这个查询无法工作,因为数据库中的参数不是 Rails 正在搜索的参数。
数据库中的通知在“供应商”(“data_source”和“added_by”)之上有额外的参数,Vendor
.这就是为什么 returns 什么都没有吗?
现在,我将通过将 vendor_id 存储在参数中并执行类似 Notification.where("params >> vendor_id = ?", 123)