【问题标题】:Nested form for has many :through join model, where join model has additional attribute嵌套形式有很多:通过连接模型,其中连接模型具有附加属性
【发布时间】:2017-07-04 06:20:05
【问题描述】:

我有两个模型通过连接模型连接。连接模型存储了一个附加属性value,它是一个布尔值A Role 有许多PermissionsRolePermissionRolePermission 存储Role 是否可以执行Permission 指示的操作。

每个Role 都应该有一个RolePermission 记录,每个Permission(其中大约有10 个)。

但是,我在创建表单时遇到了问题。我希望每个Permission 都有一个复选框,用于指示RolePermissionvalue 属性的布尔值。

型号

class Role < ApplicationRecord
    has_many :role_permissions, dependent: :destroy
    has_many :permissions, through: :role_permissions

    accepts_nested_attributes_for :role_permissions
end

class RolePermission < ApplicationRecord
    belongs_to :role
    belongs_to :permission
end

class Permission < ApplicationRecord
    has_many :role_permissions
    has_many :roles, through: :role_permissions
end

表格列

Roles
    name: string
    description: string

Permissions
    name: string
    description: string

RolePermissions
    role: references
    permission: references
    value: boolean

视图/角色/_form.html.erb

<%= form_for [@chronicle, @role], url: url do |f| %>

    ...

    <%= f.fields_for :role_permissions, Permission.all do |ff| %>
      ???
      <%= ff.label :name %>
      <%= ff.check_box :value %>
      ???
    <% end %>

    <%= f.submit text, class: 'btn btn-primary btn-block' %>
<% end %>

控制器/roles_controller.rb

class RolesController < ApplicationController
    ...

    def create
      @chronicle = Chronicle.find(params[:chronicle_id])
      @role = @chronicle.roles.build(role_params)
      ???
      @role_permissions = @role.role_permissions.build
      ???

      if @chronicle.save
        flash[:success] = 'Role successfully created.'
        redirect_to chronicle_role_url(@chronicle, @role)
      else
        render 'new'
      end
    end

    private
        def role_params
          params.require(:role).permit(:name, :description, role_permission_attributes: [] )
        end
    end
end

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-5


    【解决方案1】:

    我仍然相信中间没有 Role_permission 模型的概念。每个角色都应该有自己的权限 (has_many),但是当每个角色创建权限时,权限名称和描述会被重复使用。

    这就是我所做的。

    我在角色控制器的私有部分中使用名称和描述的值创建了一个哈希

    # roles_controller.rb
    def permission_values
      {
        "Can edit" => "This is not good if you want to party", 
        "Can show" => "Yes, yes, yes. Go ahead",
        "Can hike" => "Oh my! A hike-role?",
        "And so on" => "What do we have here?"
      }     
    end
    

    然后,当我创建角色和权限时,我使用 .build 和权限值。

    不能用 seed.rb 来做,因为必须在分配权限之前创建角色

    #roles_controller.rb
    def new
    @role = Role.new
      permission_values.each do |titel, desc| 
        @role.permissions.build(name: titel, description: desc)
      end
    end
    

    在表单中我使用.object.hidden_field 来显示和创建值。

    # _form.html.erb
    ...
    <%= f.fields_for :permissions do |ff|%>
    <h4><%= ff.object.name %></h4>
    <%= ff.hidden_field :name %>
    <p><%= ff.object.description %></p>
    <%= ff.hidden_field :description %>
    <%= ff.check_box :permitted %>
    <% end %>
    

    你有它!

    现在每个用户都将显示相同的权限,但他们可以根据需要检查是否允许并将其保存在他们的角色中。 在节目中,类似:

    # show.html.erb
    # I would make a helper-method
    # And some index-symbol-power!
    <%= "Hey! I'm permitted to do this!" if @role.permissions.find_by_name("Can 
    edit").permitted? %>
    

    注意:

    记住 role_params 中权限属性中的 :id,这样权限在编辑时不会重复。

    ================================================ ==========================

    【讨论】:

    • 你怎么看?
    【解决方案2】:

    RolePermission 模型是否必要?

    如果我误解了什么,请告诉我。为什么不在 Permission 模型上放置一个布尔属性?

    表格列:

    Roles
    name: string
    description: string
    
    Permissions
    referenced: role
    name: string
    description: string
    permitted: boolean
    

    现在你可以在 field_for 中有一个复选框字段,没有任何问题

    #In form_for [@chronicle, @role], url: url do |f|  
    ...
    <%= f.fields_for :permissions do |ff| %>
     <%= ff.label :permitted %>
     <%= ff.check_box :permitted %>
     ... <!-- description and name -->
    

    还有你的控制器

    切记不要在视图中调用 Permission.all,而是在 RolesController 中的 action new 中使用 .build。

    def new
    #Find @chronicle
    @role = Role.new
    10.times { @role.permissions.build }
    end
    
    def create 
    # If you set up your accepts_nested_attributes_for :permissions 
    # (delete the rest of role_permission stuff) in role.rb, 
    # and update your role_params with the permission_attributes everything should 
    be 
    # working fine. Find your role and save it. 
    end
    

    然后您可以执行以下操作:

    if role.permissions.first.permitted? 
    # DO SOMETHING CRAZY
    end
    

    【讨论】:

    • 我对此不确定,因为我想拥有 10 个左右的恒定权限,我可以跨角色重用。假设有三个权限:Can ViewCan EditCan CreateRole 管理员可能有RolePermissions,其中三个的值都是trueRole 版主可能有RolePermissions,其中Can ViewtrueCan Createtrue,但Can Editfalse。等等。将这些信息存储在 Roles 表中似乎并不是特别干净。
    • 您是从头开始创建登录系统吗?使用基于角色的授权?如果你是,我会查看devise gem
      这里你可以在每个控制器的顶部创建授权,例如:access all: [:show, :index], user: {except: [:destroy]}, site_admin: :all 当然你可以自己创建它,但是使用 Devise 对我来说感觉就像每次节省时间。
    • 这里并不适用。我正在使用 Sorcery 进行用户身份验证,但角色及其 RolePermissions(但不是 Permissions)是用户创建的。所以 CanCanCan/Pundit/Devise 并不适合我的用例。无论如何,这是一个让我接触 Rails 的爱好项目——我宁愿自己授权等来帮助我学习,而不是仅仅插入一个 gem。
    • 是的,好的。我明白了:) 好主意。我会再试一次 - 秒。
    猜你喜欢
    • 2011-02-17
    • 1970-01-01
    • 2011-01-12
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    相关资源
    最近更新 更多