【问题标题】:Active admin user new page got error活动管理员用户新页面出错
【发布时间】:2012-06-19 07:34:36
【问题描述】:

我有两种类型的管理员用户

  1. 超级管理员
  2. 机构管理员

使用 cancan 进行以下操作。

超级管理员可以创建机构管理员/另一个超级管理员以及与机构相关的普通用户,并且可以管理所有其他内容,例如兴趣类型、目标....等。 超级管理员也可以看到系统中创建的所有用户。

机构管理员可以创建仅与该机构相关的用户,并且只能查看与该机构相关的用户。

所以一切正常,除非有 1 件事。当我使用机构管理员登录并在页面上创建新用户时,它会显示以下错误。

ActiveRecord::HasManyThroughNestedAssociationsAreReadonly in Admin::UsersController#new 
Cannot modify association 'AdminUser#users' because it goes through more than one other association.

models/admin_user.rb

class AdminUser < ActiveRecord::Base

  belongs_to :institution
  has_many :profiles, :through => :institution
  has_many :users, :through => :profiles

  devise :database_authenticatable, 
         :recoverable, :rememberable, :trackable, :validatable

  def password_required?
    new_record? ? false : super
  end

  def all_users
    if role == "super_admin"
     User.unscoped
    else
     #may be below line of code has issue.
     users       
    end
  end
 end

models/ability.rb

class Ability
  include CanCan::Ability

  def initialize(current_admin_user)
    # Define abilities for the passed in user here. For example:

    current_admin_user ||= AdminUser.new # guest user (not logged in)

    case current_admin_user.role
    when "super_admin"  
      can :manage, :all  
    when "institution_admin"
      can :manage, User, :profile => {:institution_id => current_admin_user.institution_id}
      can :manage, InterestType, :institution_id => current_admin_user.institution_id 
    end
    end
   end

控制器/users_controller.rb

 class UsersController < ApplicationController
      layout "home"
      skip_before_filter :require_login, :only => [:new, :create, :activate]

      def new
        @user = User.new
        @user.build_profile
      end

      def create
        @user = User.new(params[:user])
        if @user.save
           redirect_to home_path, :notice => "Please check email."
        else
           render :new, :alert => @user.errors
        end
      end
    end

admin/admin_users.rb

ActiveAdmin.register AdminUser do

  menu :if => proc{ can?(:manage, AdminUser) }        controller.authorize_resource 

  index do
    column :email
    column ("Role") {|admin_user| admin_user.role == "super_admin" ? "Administrator" : "Institution Administrator" }  
    column ("Instituion") { |admin_user| admin_user.institution.name unless admin_user.institution_id.nil? }
    column :current_sign_in_at
    column :last_sign_in_at
    column :sign_in_count
    default_actions   end

  #...   form do |f|
    f.inputs "Admin Details" do
      f.input :email
      f.input :role, :as => :select, :include_blank => false, :collection => Hash[ "Institution Administrator", "institution_admin", "Administrator", "super_admin"]
      f.input :institution_id, :as => :select, :include_blank => false, :collection => Institution.all.map{ |ins| [ins.name, ins.id] }
    end
      f.buttons   end

  after_create { |admin| admin.send_reset_password_instructions unless admin.email.blank? and admin.institution_id.blank? }
    def password_required?
    new_record? ? false : super   end

end

admin/users.rb

ActiveAdmin.register User do

  menu :if => proc{ can?(:manage, User) }     
  controller.authorize_resource 
  scope_to :current_admin_user, :association_method => :all_users

  index do

    column :username
    column :email
    column ("Instituion") { |user| user.profile.institution.name }
    column :activation_state
    column("Name" ) {|user| user.profile.users_firstname + " " + user.profile.users_lastname}
    column :created_at
  end

  form do |f|

    f.inputs "User Details" do
      f.input :username
      f.input :email
      if f.object.id.nil?
          f.input :password
          f.input :password_confirmation
      end
    end

    f.inputs "Profile Details", :for => [:profile, f.object.profile || Profile.new] do |profile_form|
      profile_form.input :users_firstname
      profile_form.input :users_lastname
      profile_form.input :users_telephone
      profile_form.input :class_year, :collection => 1995..2020,  :selected => Time.now.year
      if current_admin_user.role == "super_admin"
        profile_form.input :institution_id, :as => :select, :include_blank => false, :collection => Institution.all.map{ |ins| [ins.name, ins.id] }
      elsif current_admin_user.role == "institution_admin"
        profile_form.input :institution_id, :as => :hidden, :value => current_admin_user.institution_id
      end
    end

    f.buttons
  end


end

注意:当我将 admin_users.rb 中的 def all_users 从 users 编辑到 User.scoped 我可以从机构用户创建新用户,但在索引上 页面我可以看到所有用户(而不仅仅是来自 机构)

【问题讨论】:

  • 也许您可以向我们展示 UsersController#new 方法。
  • 用控制器代码更新了我的问题
  • 我知道问题在于管理员用户和用户之间的关系,但无法解决
  • 您能否向我们展示您的用户和管理员用户的 active_admin 控制器?
  • 嗨@jon,在admin中添加了admin_users.rb和users.rb的代码

标签: ruby-on-rails-3 activeadmin


【解决方案1】:

您可以通过将all_users 中的users 行修改为:

User.joins(:profile => :institution).where(["#{Institution.table_name}.id = ?", institution.id])

这不会为新用户设置个人资料,因此您仍需要以与分配机构相同的方式在表单中分配该个人资料。您还需要确保个人资料和机构之间存在双向关联。

您收到错误的原因是 ActiveRecord 不允许您通过关联从嵌套的 has_many 中创建新记录。我们正在通过获得相同关联的结果来解决这个问题,但没有经过 has_many。该查询相当于说“获取属于个人资料的所有用户,而个人资料又是机构的一部分,其中机构的 ID 与当前用户的机构 ID 相同”。

【讨论】:

  • 不知何故它的工作,但我不明白所有表名部分的条件以及它可以从哪里获得机构ID,请你解释一下,所以我可以奖励赏金答案
  • 好的,谢谢你的解释,但我以前从未在 rails 中使用过 model.table_name 之类的东西,它有什么用?
  • 这是获取模型表名的安全方法。在您的情况下,很可能是机构,但这并不总是保证,特别是如果您使用的是旧数据库。
最近更新 更多