You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails表单:关联模型动态数据的has_many关系处理

Hey there! Let's work through this dynamic role-based user field permission problem you're facing. The core goal is to let each role only view/edit specific user fields, with support for adding new roles over time—and right now, you're stuck creating new roles because the role-association doesn't exist yet to list out user fields. Here's how to fix this:

First, Fix the Association Initialization

The main issue is that when creating a new role, there's no role_assignment record tied to it yet, so fields_for can't render properly. We need to initialize an empty role_assignment in the controller so the form has something to bind to.

Update Your Controller (RolesController)

def new
  @role = Role.new
  # Build an empty role_assignment to enable fields_for rendering
  @role.role_assignments.build
end

def edit
  @role = Role.find(params[:id])
  # Ensure there's at least one assignment for existing roles too
  @role.role_assignments.build if @role.role_assignments.empty?
end

Add Model Support for Nested Attributes

Next, configure your models to handle nested role assignment data, including the ability to delete permissions later:

app/models/role.rb

class Role < ApplicationRecord
  has_many :role_assignments, dependent: :destroy
  accepts_nested_attributes_for :role_assignments, allow_destroy: true
end

app/models/role_assignment.rb

class RoleAssignment < ApplicationRecord
  belongs_to :role
  validates :user_field, :permission_type, presence: true
end

Rewrite the Form for Dynamic Field Selection

Instead of a disabled text field (which can't submit data), we'll use a dropdown that dynamically pulls all user fields from your User model. We'll also add support for adding multiple field permissions and deleting existing ones.

Create a Partial for Role Assignment Fields (_role_assignment_fields.html.erb)

<tr>
  <td>
    <%= f.label :user_field %>
    <%# Dynamically pull all attributes from the User model %>
    <%= f.select :user_field, User.attribute_names, include_blank: false %>
  </td>
  <td>
    <%= f.label :permission_type %>
    <%= f.select :permission_type, ['view', 'edit'], include_blank: false %>
  </td>
  <td>
    <%# Only show delete option for existing permissions %>
    <% if f.object.persisted? %>
      <%= f.hidden_field :_destroy %>
      <%= link_to 'Remove', '#', class: 'remove-assignment' %>
    <% end %>
  </td>
</tr>

Update the Main Role Form

<%= form_with(model: @role, local: true) do |form| %>
  <table>
    <thead>
      <tr>
        <th>User Field</th>
        <th>Permission</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <%= form.fields_for :role_assignments do |role_assignment_form| %>
        <%= render 'role_assignment_fields', f: role_assignment_form %>
      <% end %>
    </tbody>
  </table>

  <%= link_to 'Add Field Permission', '#', id: 'add-assignment' %>
  <%= form.submit 'Save Role' %>
  <%= link_to 'Back', roles_path %>

  <%# Hidden template for dynamically adding new permissions %>
  <%= form.fields_for :role_assignments, RoleAssignment.new, child_index: 'NEW_RECORD' do |f| %>
    <%= content_tag :div, 
                    id: 'role_role_assignments', 
                    data: { fields: j(render 'role_assignment_fields', f: f) },
                    style: 'display: none' %>
  <% end %>
<% end %>

<script>
  // Add new permission row
  $(document).on('click', '#add-assignment', function(e) {
    e.preventDefault();
    var template = $('#role_role_assignments').data('fields').replace(/NEW_RECORD/g, Date.now());
    $('tbody').append(template);
  });

  // Mark permission for deletion
  $(document).on('click', '.remove-assignment', function(e) {
    e.preventDefault();
    $(this).closest('tr').find('input[name*="_destroy"]').val('1');
    $(this).closest('tr').hide();
  });
</script>

Why This Works

  • Dynamic Field List: User.attribute_names automatically pulls all fields from your User model, so you don't have to update the form when adding new user fields.
  • Association Fix: Initializing an empty role_assignment in the controller ensures fields_for renders correctly even for brand-new roles.
  • Scalability: This setup supports unlimited new roles and permission combinations—no code changes needed when adding roles later.
  • Flexibility: Admins can add/remove field permissions per role without touching backend code.

内容的提问来源于stack exchange,提问作者bonafernando

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:25:44