Rails 4 has_many :through association: use Devise current_user in other parent model after_create 回调

Rails 4 has_many :through association: use Devise current_user in other parent model after_create callback

我有三个模型,具有 has_many :through 关联:

class User < ActiveRecord::Base
  has_many :administrations
  has_many :calendars, through: :administrations
end

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

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

连接 Administration 模型具有以下属性:

id
user_id
calendar_id
role

这是我当前的路线:

devise_for :users, :path => 'account'

resources :users do
  resources :calendars
end

更新

这里是 Calendars#create 代码:

def create
    @user = current_user
    @calendar = @user.calendars.create(calendar_params)
    respond_to do |format|
      if @calendar.save
        format.html { redirect_to user_calendar_path(@user,@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

每当 user 创建一个新的 calendar 时,我想为这个特定的 user 分配一个 role — 在 administration 连接模型中 — "Owner".

我认为最好的方法是在 calendar 模型中使用 after_create 回调,如下所示:

class Calendar < ActiveRecord::Base
  has_many :administrations, dependent: :destroy
  has_many :users, through: :administrations

  after_create :set_default_role

  protected

  def set_default_role
    current_user.calendar.role = "Owner"
  end

end

但是,当我继续尝试创建新日历时,出现以下错误:

NameError in CalendarsController#create
undefined local variable or method `current_user' for #<Calendar:0x007f88f8f26998>

Extracted source (around line #10):

  def set_default_role
    current_user.calendar.role = "Owner"
  end

end

经过一些研究,我发现 this question on Quora 的答案如下:

It is not good practice for the model to directly have knowledge of the current user; this is an application 'state' or session related issue. The controllers should be managing the current user.

我不得不说我有点困惑:一般原则是通过将逻辑放在模型中来保持控制器瘦身。但是,上面的答案建议做相反的事情,因为模型不应该知道当前用户。

所以,回到我最初的问题:当用户创建新日历时,我如何为他定义默认角色?

我应该使用 after_create 回调,使用其他东西而不是 current_user 来获取他的 id,还是使用完全不同的解决方案?

更新: 该模型没有 current_user。从日历模型中删除 set_default_role 并添加到管理模型:

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

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

  before_create :set_default_role

  def set_default_role
    self.role = "Owner"
  end
end

将此添加到 CalendarsController 创建操作:

@calendar.administrations.first.role = 'Owner'

而且我认为它会起作用。

这是我最后做的。

首先,在User模型中,我定义了如下方法:

def set_default_role(calendar_id, role)
  self.administrations.find_by(calendar_id: calendar_id).update(role: role)
end

然后,我更新了Calendars#Create如下:

def create
  @user = current_user
  @calendar = @user.calendars.create(calendar_params)
  respond_to do |format|
    if @calendar.save
      current_user.set_default_role(@calendar.id, 'Owner')
      format.html { redirect_to user_calendar_path(@user,@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

现在,每当 user 创建一个新的 calendar 时,如果保存了新的 calendar,则 current_user 默认分配给 role 所有者。