Rails 4: Model:Class 的未定义方法 `relation_delegate_class'
Rails 4: undefined method `relation_delegate_class' for Model:Class
我正在尝试遵循有关 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
——————
更新 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
引起的,因为给定 user
的 role
仅存在于 administration
table,对于给定的 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
——————
更新 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
控制器中:这可能是问题的根源吗?
——————
知道此错误消息的含义以及如何解决该问题吗?
这个问题很难识别,尤其是从问题的内容来看。
问题
我收到 undefined method 'relation_delegate_class' for Invite:Class
错误的原因是 Rails 不再将 Invite
视为模型。
问题的根本原因
当我创建 Invite
邮件程序时,我 运行 rails g mailer Invite
而不是 rails g mailer InviteMailer
.
因此,Invite
作为邮件程序会覆盖 Invite
作为模型,因此一旦将方法应用于 Invite
模型的实例就会产生错误。
我们是怎么想出来的
我的一个朋友在编程方面比我更有经验,他通过调整导致错误的 @invite = @calendar.invites.build
行确定了问题。
这导致我们最终在 rails 控制台中 运行 Invite.first
:虽然我们应该得到 Invite
class 的实例,或零,我们实际上得到了一个错误。
由于 .first
应该是任何 ActiveRecord 模型上的有效方法,我们意识到 Invite
不被 Rails 视为模型。
我们是如何解决的
一旦我们确定了问题,修复它就非常简单了:
- 我们将
Invite
邮件程序的名称从 invite.rb
更改为 invite_mailer.rb
- 在新重命名的
invite_mailer.rb
文件中,我们将 class Invite < ApplicationMailer
替换为 class InviteMailer < ApplicationMailer
我希望这对可能遇到类似 relation_delegate_class
错误的其他 Stack Overflow 用户有用。
如果您忘记从 ActiveRecord 继承您的模型,也会发生这种情况。
因此它变成了一个简单的 ruby class.
class MyPlainModel
end
另一个原因是您的 sti 列指向无效列 class。我以某种方式结束了:
=> #<Mailerlite::Subscriber:0x00005559d469bd00
...
user_id: 2777,
user_type: "NilClass",
...
>
尝试加载 user
关系时导致 NoMethodError: undefined method 'relation_delegate_class' for NilClass:Class
。
通过将 user_type
列更改为 nil
或正确的 class 名称即可进行足够简单的修复。
我正在尝试遵循有关 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
——————
更新 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
引起的,因为给定 user
的 role
仅存在于 administration
table,对于给定的 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
——————
更新 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
控制器中:这可能是问题的根源吗?
——————
知道此错误消息的含义以及如何解决该问题吗?
这个问题很难识别,尤其是从问题的内容来看。
问题
我收到 undefined method 'relation_delegate_class' for Invite:Class
错误的原因是 Rails 不再将 Invite
视为模型。
问题的根本原因
当我创建 Invite
邮件程序时,我 运行 rails g mailer Invite
而不是 rails g mailer InviteMailer
.
因此,Invite
作为邮件程序会覆盖 Invite
作为模型,因此一旦将方法应用于 Invite
模型的实例就会产生错误。
我们是怎么想出来的
我的一个朋友在编程方面比我更有经验,他通过调整导致错误的 @invite = @calendar.invites.build
行确定了问题。
这导致我们最终在 rails 控制台中 运行 Invite.first
:虽然我们应该得到 Invite
class 的实例,或零,我们实际上得到了一个错误。
由于 .first
应该是任何 ActiveRecord 模型上的有效方法,我们意识到 Invite
不被 Rails 视为模型。
我们是如何解决的
一旦我们确定了问题,修复它就非常简单了:
- 我们将
Invite
邮件程序的名称从invite.rb
更改为invite_mailer.rb
- 在新重命名的
invite_mailer.rb
文件中,我们将class Invite < ApplicationMailer
替换为class InviteMailer < ApplicationMailer
我希望这对可能遇到类似 relation_delegate_class
错误的其他 Stack Overflow 用户有用。
如果您忘记从 ActiveRecord 继承您的模型,也会发生这种情况。 因此它变成了一个简单的 ruby class.
class MyPlainModel
end
另一个原因是您的 sti 列指向无效列 class。我以某种方式结束了:
=> #<Mailerlite::Subscriber:0x00005559d469bd00
...
user_id: 2777,
user_type: "NilClass",
...
>
尝试加载 user
关系时导致 NoMethodError: undefined method 'relation_delegate_class' for NilClass:Class
。
通过将 user_type
列更改为 nil
或正确的 class 名称即可进行足够简单的修复。