Thi*_*ent 11 model-view-controller activerecord ruby-on-rails nomethoderror ruby-on-rails-4
我正在尝试按照这个关于为Rails创建一个Scoped邀请系统的 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
Run Code Online (Sandbox Code Playgroud)
以下是我的模型与教程中的模型之间的对应关系:
User <=> UserCalendar <=> UserGroupAdministration <=> MembershipInvite <=> 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
Run Code Online (Sandbox Code Playgroud)
问题似乎来自这@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
Run Code Online (Sandbox Code Playgroud)
-----
更新2:在这个问题中,作者解释了问题可能来自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
Run Code Online (Sandbox Code Playgroud)
我想知道问题是否可能是由于t.string :recipient_role,由于role给定的user只存在于administration表中,对于给定的calendar:如果:recipient_role被recipient.roleRails 自动解释,那么这可能导致错误?
-----
更新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
Run Code Online (Sandbox Code Playgroud)
-----
更新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)
Run Code Online (Sandbox Code Playgroud)
-----
更新6:我刚刚意识到我没有
def invite_params
params.require(:invite)
end
Run Code Online (Sandbox Code Playgroud)
在Invites控制器中:这可能是问题的根源吗?
-----
有关此错误消息的含义以及如何解决问题的任何想法?
Thi*_*ent 20
The problem was tricky to identify, especially just from the content of the question.
THE PROBLEM
The reason why I was getting the undefined method 'relation_delegate_class' for Invite:Class error is because Invite was no longer considered to be a model by Rails.
THE ROOT CAUSE OF THE PROBLEM
When I created the Invite mailer, I ran rails g mailer Invite instead of rails g mailer InviteMailer.
Because of this, Invite as a mailer override Invite as a model, hence creating errors as soon as methods were applied to instances of the Invite model.
HOW WE FIGURED IT OUT
One of my friends, who is way more experienced with programming than I am, identified the problem by tweaking the @invite = @calendar.invites.build line that was causing the error.
This led us to eventually run Invite.first in the rails console: while we should have got either an instance of the Invite class, or nil, we actually got an error.
Since .first should be a valid method on any ActiveRecord model, we realized that Invite was not a considered to be a model by Rails.
HOW WE FIXED IT
Once we had identified the issue, fixing it was pretty straightforward:
Invite mailer from invite.rb to invite_mailer.rbinvite_mailer.rb file, we replaced class Invite < ApplicationMailer with class InviteMailer < ApplicationMailerI hope this can be useful to other Stack Overflow users who might get a similar relation_delegate_class error.