Rails 4:模型:类的未定义方法“relation_delegate_class”

Posted

技术标签:

【中文标题】Rails 4:模型:类的未定义方法“relation_delegate_class”【英文标题】:Rails 4: undefined method `relation_delegate_class' for Model:Class 【发布时间】:2015-12-10 19:15:22 【问题描述】:

我正在尝试关注这个关于 Creating a Scoped Invitation System for Rails 的 coderwall 教程。

在我的 Rails 4 应用程序中,我有以下模型:

class User < ActiveRecord::Base
  has_many :administrations
  has_many :calendars, through: :administrations
  has_many :invitations, :class_name => "Invite", :foreign_key => 'recipient_id'
  has_many :sent_invites, :class_name => "Invite", :foreign_key => 'sender_id'
end

class Calendar < ActiveRecord::Base
  has_many :administrations
  has_many :users, through: :administrations
  has_many :invites
end

class Administration < ActiveRecord::Base
  belongs_to :user
  belongs_to :calendar
end

class Invite < ActiveRecord::Base
  belongs_to :calendar
  belongs_to :sender, :class_name => 'User'
  belongs_to :recipient, :class_name => 'User'
end

这是我的模型和教程中的模型之间的对应关系:

User User Calendar UserGroup Administration Membership Invite Invite

我现在在发出新邀请部分:

Invite 模型已更新为 before_create 过滤器和 generate_token 方法。 Invites 控制器已更新为 create 操作。

但是,当我访问日历编辑视图以填写邀请表单时,我收到以下错误:

NoMethodError in CalendarsController#edit
undefined method `relation_delegate_class' for Invite:Class
def edit
  @user = current_user
  @invite = @calendar.invites.build
  authorize @calendar
end

问题似乎来自@invite = @calendar.invites.build 行。

————

更新:这是我的邀请模型的内容:

class Invite < ActiveRecord::Base
  belongs_to :calendar
  belongs_to :sender, :class_name => 'User'
  belongs_to :recipient, :class_name => 'User'

  before_create :generate_token

  def generate_token
   self.token = Digest::SHA1.hexdigest([self.calendar_id, self.recipient_role, Time.now, rand].join)
  end

end

————

UPDATE 2:在this question,作者解释问题可能来自CanCanCan & Rolify。我不使用这些宝石,但我使用 Pundit。认为这对我的问题很有用。

————

更新 3:这也是我用于 Invite 模型的迁移:

class CreateInvites < ActiveRecord::Migration
  def change
    create_table :invites do |t|
      t.string :email 
      t.integer :calendar_id
      t.integer :sender_id
      t.integer :recipient_id
      t.string :recipient_role
      t.string :token
      t.timestamps null: false
    end
  end
end

我想知道问题是否可能是由t.string :recipient_role 引起的,因为给定userrole 仅存在于administration 表中,对于给定的calendar:如果:recipient_role 是Rails 自动将其解释为recipient.role,那么这可能是导致错误的原因吗?

————

更新 4:这是 CalendarsController 的内容:

class CalendarsController < ApplicationController
  before_action :set_calendar, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

  # GET /calendars
  # GET /calendars.json
  def index
    @user = current_user
    @calendars = @user.calendars.all
  end

  # GET /calendars/1
  # GET /calendars/1.json
  def show
    @user = current_user
    @calendar = @user.calendars.find(params[:id])
    authorize @calendar
  end

  # GET /calendars/new
  def new
    @user = current_user
    @calendar = @user.calendars.new
    authorize @calendar
  end

  # GET /calendars/1/edit
  def edit
    @user = current_user
    @invite = @calendar.invites.build
    authorize @calendar
  end

  # POST /calendars
  # POST /calendars.json
def create
  @user = current_user
  @calendar = @user.calendars.create(calendar_params)
  authorize @calendar
  respond_to do |format|
    if @calendar.save
      current_user.set_default_role(@calendar.id, 'Owner')
      format.html  redirect_to calendar_path(@calendar), notice: 'Calendar was successfully created.' 
      format.json  render :show, status: :created, location: @calendar 
    else
      format.html  render :new 
      format.json  render json: @calendar.errors, status: :unprocessable_entity 
    end
  end
end

  # PATCH/PUT /calendars/1
  # PATCH/PUT /calendars/1.json
  def update
    @user = current_user
    @calendar = Calendar.find(params[:id])
    authorize @calendar
    respond_to do |format|
      if @calendar.update(calendar_params)
        format.html  redirect_to calendar_path(@calendar), notice: 'Calendar was successfully updated.' 
        format.json  render :show, status: :ok, location: @calendar 
      else
        format.html  render :edit 
        format.json  render json: @calendar.errors, status: :unprocessable_entity 
      end
    end
  end

  # DELETE /calendars/1
  # DELETE /calendars/1.json
  def destroy
    @user = current_user
    @calendar.destroy
    authorize @calendar
    respond_to do |format|
      format.html  redirect_to calendars_url, notice: 'Calendar was successfully destroyed.' 
      format.json  head :no_content 
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_calendar
      @calendar = Calendar.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def calendar_params
      params.require(:calendar).permit(:name)
    end
end

————

UPDATE 5:这里是服务器日志:

Started GET "/calendars/2/edit" for ::1 at 2015-09-14 11:44:13 -0700
Processing by CalendarsController#edit as HTML
  Parameters: "id"=>"2"
  Calendar Load (0.1ms)  SELECT  "calendars".* FROM "calendars" WHERE "calendars"."id" = ? LIMIT 1  [["id", 2]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.3ms)

NoMethodError (undefined method `relation_delegate_class' for Invite:Class):
  app/controllers/calendars_controller.rb:30:in `edit'


  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1@global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_source.erb (6.0ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1@global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.8ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1@global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.7ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1@global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (68.9ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.5ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (39.3ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.4ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.4ms)
  Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (94.2ms)

————

更新 6:我才意识到我没有

def invite_params
  params.require(:invite)
end

Invites 控制器中:这可能是问题的根源吗?

————

您知道此错误消息的含义以及如何解决此问题吗?

【问题讨论】:

你能显示你得到的错误的完整回溯吗?如果我能看到您的 CalendarsController 的内容也会很有帮助。谢谢。 当然,我刚刚添加了CalendarsController 的完整代码和服务器日志。如果您需要任何其他信息,请告诉我。 我没有看到任何明显的东西。尝试更新所有宝石。尝试在invites 关联上硬编码一个类名。尝试注释掉所有关联,然后一次取消注释它们,直到它中断。 非常感谢詹姆斯,非常感谢。我会尝试你的建议。 【参考方案1】:

这个问题很难识别,尤其是从问题的内容来看。

问题

我收到 undefined method 'relation_delegate_class' for Invite:Class 错误的原因是 Invite 不再被 Rails 视为模型。

问题的根本原因

当我创建Invite 邮件程序时,我运行的是rails g mailer Invite 而不是rails g mailer InviteMailer

因此,Invite 作为邮件程序会覆盖 Invite 作为模型,因此一旦将方法应用于 Invite 模型的实例就会产生错误。

我们是怎么想出来的

我的一个朋友在编程方面比我更有经验,他通过调整导致错误的 @invite = @calendar.invites.build 行发现了问题。

这导致我们最终在 Rails 控制台中运行 Invite.first:虽然我们应该得到 Invite 类的实例或 nil,但我们实际上得到了一个错误。

由于.first 应该是任何 ActiveRecord 模型上的有效方法,我们意识到 Invite 不被 Rails 视为模型。

我们是如何解决的

一旦我们确定了问题,修复它就非常简单:

我们将 Invite 邮件程序的名称从 invite.rb 更改为 invite_mailer.rb 在新重命名的invite_mailer.rb 文件中,我们将class Invite &lt; ApplicationMailer 替换为class InviteMailer &lt; ApplicationMailer

我希望这对可能遇到类似relation_delegate_class 错误的其他 Stack Overflow 用户有用。

【讨论】:

非常感谢 K M Rakibul Islam。花了一些时间,但我们修复了它! 使用名为邀请的邮件程序遇到了完全相同的问题。感谢您的详细回答并为我节省了一些时间。 谢谢!我的项目存在同样的“命名”问题。感谢详细的回复。 我遇到了同样的问题,它实际上与我们为 API 消息命名为“Messager.rb”的类有关。几个月后,我们创建了一个名为“Message”的模型并收到此错误。我很快就发现这是因为我们有 2 个同名的类。命名是关键,大声笑...将 Message 重命名为 ApiMessage.rb【参考方案2】:

如果您忘记从 ActiveRecord 继承模型,也会发生这种情况。 因此它变成了一个简单的 ruby​​ 类。

class MyPlainModel
end

【讨论】:

【参考方案3】:

另一个原因是您的 sti 列指向无效的列类。我以某种方式结束了:

=> #<Mailerlite::Subscriber:0x00005559d469bd00
...
 user_id: 2777,
 user_type: "NilClass",
...
>

在尝试加载user 关系时导致NoMethodError: undefined method 'relation_delegate_class' for NilClass:Class

只需将user_type 列更改为nil 或正确的类名即可轻松解决。

【讨论】:

以上是关于Rails 4:模型:类的未定义方法“relation_delegate_class”的主要内容,如果未能解决你的问题,请参考以下文章

升级到 Rails 4.2.5.1 后 nil:NilClass 的未定义方法“缓存”

Rails 3 - application.html.erb 中 nil:NilClass 的未定义方法“[]”

Squeel 在 Rails 控制台中工作,但不在控制器中。错误:nil:NilClass 的未定义方法“方法”

Ruby on Rails Simple_form_for的未定义方法

升级到 Rails 6.1.0 后 ActiveStorage::Blob 的未定义方法“service_name”

简单的未定义方法错误 - Rails