【问题标题】:Setting Default Role using Enum based on Project creation基于项目创建使用枚举设置默认角色
【发布时间】:2016-07-08 16:17:31
【问题描述】:

我有一个项目和一个关系模型来在用户和项目之间建立“跟随”关系。我在关系模型中使用枚举为“关系”建立了三个角色……它们是管理员、协作者和访问者。但是,我需要根据建立用户和项目之间关系的方式来设置默认角色。需要以下简单场景:

(a) 创建项目的用户会自动关注该项目...在创建项目时,应将关系角色设置为“管理员”

(b) 如果网站的访问者只是导航到项目资料页面,他们可以单击“关注”按钮建立关注关系...但是这应该将关系角色设置为“访问者”

关系模型:

class Relationship < ActiveRecord::Base
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "Project"
  validates :follower_id, presence: true
  validates :followed_id, presence: true

  enum role: [:admin, :collaborator, :visitor]
  after_initialize :set_default_role, :if => :new_record?

  def set_default_role
    self.role ||= :admin
  end
end

关系控制器:

class RelationshipsController < ApplicationController
  before_filter :authenticate_user!

  def create
    @project = Project.find(params[:relationship][:followed_id])
    current_user.follow!(@project)
    # relationship.visitor! View railsapps documentation for devise pundit#roles
    redirect_to @project
  end

  def destroy
    @project = Project.find(params[:id]).followed
    current_user.unfollow!(@project)
    redirect_to @project
  end

  private

  def relationship_params
    params.require(:relationship).permit(:followed_id, :follower_id)
  end

项目控制器

class ProjectsController < ApplicationController
  before_filter :authenticate_user!, only: [:create, :new, :edit, :update, :delete, :followers]

def create
    @project = current_user.own_projects.build(project_params)
    if @project.save
      if params[:project][:projectimage].present?
        render :crop
      else
        flash[:success] = "You've successfully created a project..."
        redirect_to @project
      end
    else
      render 'new'
    end
  end

  def update
    @project = Project.find(params[:id])
    if @project.update_attributes(project_params)
      if params[:project][:projectimage].present?
        render :crop
      else
        flash[:success] = "Project Created"
        redirect_to @project
        @project.followers << current_user #this establishes the following relationship as soon as a new project is created between user/project
      end
    else
      render 'edit'
    end
  end

end

用户模型:

class User < ActiveRecord::Base
  has_many :own_projects, :class_name=>'Project'

  has_many :projects
  has_many :relationships, foreign_key: "follower_id", dependent: :destroy

  has_many :followed_projects, through: :relationships, source: :followed
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  def following?(some_project)
   relationships.find_by_followed_id(some_project.id)
  end

  def follow!(some_project)
   self.relationships.create!(followed_id: some_project.id)
   relationship.visitor!
  end

end

为了根据上述两种情况将默认角色设置为“管理员”或“访客”,我需要在代码中进行哪些更改?

【问题讨论】:

  • 在创建新的Relationship 时为什么不简单地指定role?如果在不同条件下(关系外部)不同,为什么还要使用默认值?
  • 是的,我就是这个意思。您基本上可以在创建关系的任何位置设置相关的role,例如在User 中的follow! 方法中:self.relationships.create!(followed_id: some_project.id, role: :visitor),或在控制器中。
  • 一个原因可能是role 的基础表列不是整数。它不能是字符串列,而是整数,因为枚举值会自动从符号(字符串)映射到整数。
  • 嗯,我不知道这里...我只是测试了我自己的简单枚举,它按我上面所说的那样工作。您能否将类似的validates presence 添加到role 的关系模型中,然后查看是否创建了记录?
  • 啊哈,我想我开始看到导致您在关系模型中使用默认值的问题。 ProjectUser 之间实际上存在 has_many :through 关系!并且 AFAIK,您不能通过简单地使用 &lt;&lt; 添加到集合来设置其他属性。您必须手动创建关系,参见例如this post 了解如何做到这一点。

标签: ruby-on-rails ruby-on-rails-4 enums roles pundit


【解决方案1】:

正如上述 cmets 中所讨论的,我认为您应该在创建 Relationships 时明确声明 role,因为角色在 @987654325 不固有的条件下有所不同@类。

现在,由于 Relationshiphas many :through 关联 UserProject 模型之间的中间人,您不能简单地使用标准方式将用户连接到使用 &lt;&lt; 的项目,但必须 明确构造中间人Relationship,包括您的自定义参数(例如角色)。

您的解决方案应该类似于posted here

class Project < ActiveRecord::Base
  has_many :relationships, foreign_key: :followed_id, dependent: :destroy
  has_many :users, through: :relationships
end

class User < ActiveRecord::Base
  has_many :relationships, foreign_key: :follower_id, dependent: :destroy
  has_many :projects, through: :relationships

  # this will create the relationship association with the 'visitor' role
  def follow_project!(some_project)
    self.relationships.create!(followed_id: some_project.id, role: :visitor)
    # I think you can even omit the ids here and work with objects:
    # self.relationships.create!(followed: some_project, role: :visitor)
  end

  # this will create the relationship association with the 'admin' role
  def administrate_project!(some_project)
    self.relationships.create!(followed: some_project, role: :admin)
  end

  # this will create the relationship association with the 'collaborator' role
  def collaborate_on_project!(some_project)
    self.relationships.create!(followed: some_project, role: :collaborator)
  end
end

class Relationship < ActiveRecord::Base
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "Project"

  enum role: [:admin, :collaborator, :visitor]
end

follow_administrate_collaborate_on_project! 方法的工作方式相同,但各自在关系中设置不同的角色。然后,您可以简单地从控制器中调用相应的控制器,例如在创建项目时设置“管理员”关系:

class ProjectsController < ApplicationController

  def create        
    # ideally you should wrap multiple separate saves in a transaction so that
    # either they all succeed or all fail
    Project.transaction do
      # this creates a barebone project, without any association
      @project = Project.create!(project_params)
      # this associates the project to the current user with admin role
      current_user.administrate_project!(@project)
      # ...                 
    end
  end

end

还请务必仔细阅读 :through 关联中的rails guides

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 2019-07-08
    • 2015-11-08
    • 2021-03-26
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多