无法修改关联'User#roles',因为源反射类'Role'通过:has_many与'Profile'相关联

时间:2016-02-21 09:34:48

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

我有三个模型,一个用户,一个个人资料和一个角色,我正在尝试通过个人资料向用户添加多个角色

# 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',因为源反射   class“Role”通过以下方式与“Profile”相关联:has_many。

我一直在看问题几个小时,但我似乎无法找到错误。

1 个答案:

答案 0 :(得分:2)

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

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