【问题标题】:Cannot modify association 'User#roles' because the source reflection class 'Role' is associated to 'Profile' via :has_many无法修改关联“用户#角色”,因为源反射类“角色”通过:has_many 关联到“配置文件”
【发布时间】:2016-02-21 09:34:47
【问题描述】:

我有三个模型,一个用户、一个配置文件和一个角色,我试图通过 配置文件 将多个角色附加到一个用户强>。

# user.rb
class User < ActiveRecord::Base
  has_one :profile, dependent: :destroy
  has_many :roles, through: :profile
  has_many :interests, through: :profile
  has_many :industries, through: :profile
end

# profile.rb
class Profile < ActiveRecord::Base
  has_one :user, dependent: :destroy
  has_many :roles
  has_many :interests
  has_many :industries
end

# role.rb
class Role < ActiveRecord::Base
  has_many :profiles
  has_many :users, :through => :profiles
  has_many :users
end

我正在尝试在 edit.html.erb (simple_form_for)

中使用以下内容
<%= f.association :roles,
                   as: :check_boxes,
                   label_method: :name,
                   value_method: :id,
                   label: 'Roles' %>

使用以下参数

params.require(:user).permit([:email, :first_name, :last_name, :admin, :password, role_ids: [] ])

我的编辑/更新方法:

  # GET /users/1/edit
  def edit
    @user.build_profile if @user.profile.nil?
  end

  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

给我以下错误信息

无法修改关联“User#roles”,因为源反射 “角色”类通过 :has_many 关联到“个人资料”。

我已经研究这个问题几个小时了,但我似乎找不到错误。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4


    【解决方案1】:

    您定义关系的方式存在几个问题。

    has_one 将外键放在关系的反面。因此,如果您在两端声明与has_one 的关系,ActiveRecord 将无法加载关联。相反,您需要在带有外键的一侧使用belongs_to

    # user.rb
    class User < ActiveRecord::Base
      has_one :profile, dependent: :destroy
    end
    
    # profile.rb
    class Profile < ActiveRecord::Base
      belongs_to :user, dependent: :destroy
    end
    

    当涉及到用户和角色时,您在双方都声明了 has_many,但没有告诉 ActiveRecord 将关系存储在哪里。在双向多对多关系中,您需要使用 has_many through: 和连接模型或 has_and_belongs_to_many

    通常在构建基于角色的访问系统时,您需要定义关系,以便角色belongs_to 单个用户而不是单个Admin 角色,例如多个用户。这允许您将角色范围限定为资源,并使添加/删除角色的逻辑变得不那么复杂(您正在向/从用户添加(或删除)角色,而不是从角色中添加或删除用户。)

    如果您正在验证/授权用户模型,您不想使用has_many :roles, through: :profiles - 三方连接会慢得多,并增加不必要的复杂性和间接性。

    如果您确实需要一个“个人资料”表,则将其用于有关用户的辅助信息,并在需要时加入它。

    class User < ActiveRecord::Base
      has_many :roles, 
      has_one :profile, dependent: :destroy
    end
    
    # Columns:
    # - user_id [integer, index, foreign key]
    # - resource_id [integer, index]
    # - resource_type [string, index]
    class Role < ActiveRecord::Base
      belongs_to :user, dependent: :destroy
      belongs_to :resource, polymorphic: true, 
                            dependent: :destroy
    end
    
    # Columns:
    # - user_id [integer, index, foreign key]
    class Profile < ActiveRecord::Base
      belongs_to :user
      # this is option but can be useful
      has_many :roles, through: :user
    end
    

    我真的建议你先阅读官方的rails guides article on associations

    【讨论】:

    • 在这种情况下,“角色”可以读作“职业”(我将把它重命名为),并且我将按照预期使用“角色”(现在为此目的使用 UserRole)。这个想法是,“用户”可以是“教师”、“学生”或“管理员”,它们将有许多“职业”、“兴趣”和“行业”,它们依次与“课程”相匹配,从而创造关系老师学生。和我在一起吧,因为我才用 Ruby 编程几个月。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    相关资源
    最近更新 更多