【发布时间】:2021-09-25 09:28:45
【问题描述】:
我有一个多态关联,可以在 rails 控制台中正常工作,但无论我如何构造它,从控制器调用时都无法正常工作。
基本代码:
# in property.rb
has_many :property_contacts, as: :property_contactable, dependent: :destroy
has_many :contacts, through: :property_contacts
# in property_contact.rb
belongs_to :contact, optional: true
belongs_to :property_contactable, polymorphic: true, optional: true
# in properties_controller.rb
def show
@property = Property.find(params[:id])
end
# in schema.rb
create_table "property_contacts", force: :cascade do |t|
t.bigint "property_id" # old, before polymorphic relationship added, will remove after data migration
t.bigint "contact_id"
t.string "property_contactable_type"
t.bigint "property_contactable_id"
# ...
end
# and output from psql, just to show that there doesn't appear to be any disconnect between the schema and postgres itself
# project_name_development=# \d property_contacts
# Table "public.property_contacts"
# Column | Type | Collation | Nullable | Default
# ---------------------------+--------------------------------+-----------+----------+-----------------------------------------------
# property_id | bigint | | |
# contact_id | bigint | | |
# # ...
# property_contactable_type | character varying | | |
# property_contactable_id | bigint | | |
在视图中,如果我调用@property.property_contacts,我会收到此错误:
ActiveRecord::StatementInvalid - PG::UndefinedColumn: ERROR: column property_contacts.property_contactable_id does not exist
LINE 1: ...operty_contacts".* FROM "property_contacts" WHERE "property_...
^:
如果我强制查询在控制器本身中运行(使用类似 @property_contacts = @property.property_contacts.load 的东西),那么
我在控制器中指向该行时遇到相同的错误。
如果我从查询中省略 property_contactable_id 并仅基于 property_contactable_type 列构建查询,则会收到一条错误消息,指出 property_contactable_type 列也不存在。
如果我尝试绕过关联并直接构建查询,像这样,我会得到同样的错误:
# in controller:
@property = Property.find(params[:id])
@property_contacts = PropertyContact.for(@property)
# in property_contact.rb
def self.for(property)
# tried both versions, same result
# where("property_contactable_id = ? AND property_contactable_type LIKE ?", property.id, property.class.name)
# where("property_contacts.property_contactable_id = ? AND property_contacts.property_contactable_type LIKE ?", property.id, property.class.name)
end
但是,当我从 rails 控制台运行它们时,所有这些都运行良好,例如:
property = Property.find(123)
# both versions work
property_contacts = property.property_contacts
property_contacts = PropertyContact.for(property)
如果我在查询中调用 to_sql,我得到的输出与控制器中的调用与控制台中的调用略有不同:
# from console:
"SELECT \"property_contacts\".* FROM \"property_contacts\" WHERE \"property_contacts\".\"property_contactable_id\" = 4675010 AND \"property_contacts\".\"property_contactable_type\" = 'Property'"
# from controller:
"SELECT \"property_contacts\".* FROM \"property_contacts\" WHERE (property_contacts.property_contactable_id = 4675010 AND property_contacts.property_contactable_type = 'Property')"
我尝试在我的控制器中运行这些查询的原始 sql 版本并得到相同的错误。我尝试过的一些不同的变体:
sql = "SELECT \"property_contacts\".* FROM \"property_contacts\" WHERE \"property_contacts\".\"property_contactable_id\" = #{@property.id} AND \"property_contacts\".\"property_contactable_type\" = 'Property'"
sql = "SELECT property_contacts.* FROM property_contacts WHERE property_contacts.property_contactable_id = #{@property.id} AND property_contacts.property_contactable_type = '#{@property.class.name}' ORDER BY property_contacts.created_at desc"
sql = "SELECT property_contacts.* FROM property_contacts WHERE property_contactable_id = #{@property.id} AND property_contactable_type = '#{@property.class.name}'"
sql = "SELECT property_contacts.* FROM property_contacts WHERE property_contacts.property_contactable_type = '#{@property.class.name}' ORDER BY property_contacts.created_at desc"
sql = "SELECT \"property_contacts\".* FROM \"property_contacts\" WHERE \"property_contacts\".\"property_contactable_id\" = 4675010 AND \"property_contacts\".\"property_contactable_type\" = 'Property'"
@property_contacts = PropertyContact.find_by_sql(sql)
@property_contacts = ActiveRecord::Base.connection.execute(sql)
谁能发现我做错了什么,或者给我一些我可以尝试的建议?
【问题讨论】:
-
确保
proptery_contacts中的记录正确设置了property_contactable_type。如果为 NULL,则可能有问题。既然您是从property_id迁移的,这是有可能的。 -
@MarlinPierce 谢谢,这是一个很好的建议,也是我一直关注的事情之一。它最终成为在不同模式版本之间切换的现有多租户模块的问题,所以我基本上是在与表的两个不同版本进行交互。
标签: ruby-on-rails postgresql activerecord