Rails中Attachment类与sendgrid-ruby冲突问题求助
这个错误的根源很明确:你项目里的Attachment模型和sendgrid-ruby库内置的SendGrid::Attachment类发生了命名冲突。当你执行include SendGrid时,会把SendGrid模块下的所有常量(包括Attachment)引入到当前上下文,导致Rails加载你的自定义模型时,发现全局已经存在一个同名的Attachment类,且它的父类和你的模型父类不一致,从而抛出超类不匹配的错误。
不用修改模型名称的解决办法有以下几种,按推荐程度排序:
1. 使用SendGrid类的完整命名空间,避免全局引入
这是最稳妥的方案,不需要修改任何模型代码,只需要调整你的SendGridEmail类代码,去掉include SendGrid,所有SendGrid相关的类都使用完整的SendGrid::前缀:
require 'sendgrid-ruby' class SendGridEmail def initialize end def send_message mail = SendGrid::Mail.new mail.from = SendGrid::Email.new(email: 'test@example.com') mail.subject = 'I\'m replacing the subject tag' personalization = SendGrid::Personalization.new personalization.add_to(SendGrid::Email.new(email: 'cannon.moyer@treadmilldoctor.com')) personalization.add_substitution(SendGrid::Substitution.new(key: '-name-', value: 'Example User')) personalization.add_substitution(SendGrid::Substitution.new(key: '-city-', value: 'Denver')) mail.add_personalization(personalization) mail.add_content(SendGrid::Content.new(type: 'text/html', value: 'I\'m replacing the <strong>body tag</strong>')) mail.template_id = '7fd8c267-9a3c-4093-8989-3df163e87c47' sg = SendGrid::API.new(api_key: "xxxxxxxxxxxxxxxxxxxxxx") begin response = sg.client.mail._("send").post(request_body: mail.to_json) rescue Exception => e puts e.message end puts response.status_code puts response.body puts response.headers end def create_notification @customer.notifications.create(name: "Manually Text Job to Customer", to: "+1", notification_type: "Manual Job Notification") end end
这样修改后,SendGrid的Attachment类只会存在于SendGrid命名空间下,不会和你全局的Attachment模型产生冲突,Rails可以正常加载你的自定义模型。
2. 仅在局部上下文引入SendGrid(谨慎使用)
如果你确实想保留include SendGrid的写法,可以确保只在SendGridEmail类内部引入,而不是在全局范围(比如初始化文件)引入。这样SendGrid的常量只会在这个类的上下文里生效,不会污染全局命名空间:
require 'sendgrid-ruby' class SendGridEmail include SendGrid # 仅在类内部引入 def initialize end # 后续代码保持不变... end
注意:这种方法的前提是你没有在其他地方(比如初始化脚本、其他控制器/模型)执行include SendGrid,否则还是会触发冲突。
3. 给自定义模型添加命名空间(可选)
如果你愿意调整模型的引用方式但不想改模型名,可以给你的Attachment模型添加命名空间,比如:
# app/models/app/attachment.rb module App class Attachment < ApplicationRecord self.table_name = 'attachments' # 保持原数据库表名不变 # 原模型代码... end end
之后在项目中引用时使用App::Attachment代替Attachment,这样也能避开和SendGrid类的冲突。不过这种方法需要修改所有引用该模型的地方,相对麻烦一些。
内容的提问来源于stack exchange,提问作者Cannon Moyer

