【问题标题】:Create and update with nested models using strong parameters Rails使用强参数 Rails 创建和更新嵌套模型
【发布时间】:2014-10-24 06:15:58
【问题描述】:

这是我的 3 个模型。

User
    has_many :memberships
    has_many :teams, through: :memberships, dependent: :destroy
    accepts_nested_attributes_for :memberships

Team
    has_many :memberships
    has_many :users, through: :memberships, dependent: :destroy
    accepts_nested_attributes_for :memberships

Membership
    belongs_to :team
    belongs_to :user

这是我的团队控制器的一些部分。我的目标是向某个团队添加/更新成员。请注意,添加成员的来源已经作为一组用户存在。

TeamsController
    def create
        @team = Team.new(team_params)
        @team.users << User.find(member_ids) #add leader and members to team
        if @team.save 
            #redirect to created team
        else
            #show errors
        end
    end

    def update
        #TO DO: update team roster here
        if @team.update(team_params)
            #redirect to updated team
        else
            #show errors
        end
    end

团队控制器的强大参数

#parameters for team details
def team_params
    params.require(:team).permit(:name, :department)
end

#parameters for members (includes leader)
def members_params
    params.require(:team).permit(:leader, members:[])
end

#get id values from members_params and store in an array
def member_ids
    members_params.values.flatten
end

对于表格,我只有:

  1. 姓名(文本字段)
  2. 部门(组合框)
  3. 领导者(组合框,根据所选部门生成选项,作为所选用户的用户 ID 提交)
  4. 成员(组合框,多个,根据所选部门生成选项,作为所选用户的用户 ID 数组提交)

我可以在我的创建过程中成功创建一个团队,并通过验证(团队和成员模型)。但是,我不知道如何更新团队,因为如果我使用 @team.users.clear 然后简单地从创建中执行相同的操作(我知道,这样做有点愚蠢),它会验证,但它会保存不管有没有错误。

表格代码

<%= form_for(@team, remote: true) do |f| %>

    <%= f.label :name, "Name" %>
    <%= f.text_field :name %>

    <%= f.label :department, "Department" %>
    <%= f.select :department, options_for_select(["Architectural", "Interior Design"], department), include_blank: true %>

    <%= f.label :leader, "Leader" %>
    <%= f.select :leader, select_leaders(department, @team.id), {include_blank: true, selected: pre_select(:leader)} %>

    <%= f.label :members, "Members" %>
    <%= f.select :members, select_members(department, @team.id), {include_blank: true}, {id: "team_members", multiple: :multiple,  data: {member_ids: pre_select(:members)}}%>

<% end %>

表格备注:

  1. 此表单适用于空白表单和填充表单。
  2. :members 字段已启用 select2。

所以我的问题是:

  1. 如何更新团队成员?是否可以根据我目前的强大参数进行更新,还是需要对其进行修改?
  2. 我的创建方法也要修改吗?

导致解决方案的一些选项

选项 #1(迄今为止最好的解决方案)

我只是为此做了一个急救解决方案,所以我认为有比我在下面所做的更好的方法。我在这里所做的是以从 member_ids 中找到的用户作为值来创建用户参数。

TeamsController
    def create
        team = Team.new(team_params.merge({users: User.find(member_ids)}))
        ...
    end

    def update
        ...
        if @team.update(team_params.merge({users: User.find(member_ids)}))
        ..
    end

选项#2

独立于解决方案 1,我只有 team_params 作为强参数。

TeamsController
    ...
    private
        def team_params
            params.require(:team).permit(:name, :department, :leader, members:[])
        end   

我为领导者和成员创建了 setter 方法。但似乎成员覆盖了领导者设置器,因为我对两个设置器都使用了update 方法,并且更新使用了相同的资源,即用户。使用此选项似乎可以解决问题。

Team
    ...
    def leader=(leader_id)
        #self.update(users: User.find(leader_id))
    end

    def members=(members_ids)
        #self.update(users: User.find(members_id))
    end

【问题讨论】:

  • 请张贴您的表单代码,通过更清晰地关联代码,帮助其他人了解您的问题。
  • 不清楚,为什么你有 2 个选择(一个为领导者,一个为成员),然后不存储领导者的任何地方。
  • 将成员划分为领导者和成员,以便用户更好地理解表格。所有成员(无论是领导者还是成员)都通过成员模型作为一个整体存储为成员。我编辑了我的帖子,所以你可以看到我到目前为止所做的尝试。
  • 添加所有用户时如何区分领导和成员:@team.users &lt;&lt; User.find(member_ids)?你还有其他专栏吗?
  • 没有任何区别。对于memberships 表,我只有team_id 和user_id。

标签: ruby-on-rails ruby nested-attributes has-many-through strong-parameters


【解决方案1】:

因为,在您的场景中,领导者和成员并没有太大的不同。您可以将模型和视图形式更改为以下内容:

class Team < ActiveRecord::Base
  has_many :memberships
  has_many :users, through: :memberships, dependent: :destroy
  accepts_nested_attributes_for :memberships
end

class User < ActiveRecord::Base
  has_many :memberships
  has_many :teams, through: :memberships, dependent: :destroy
end

class Membership < ActiveRecord::Base
  belongs_to :team
  belongs_to :user
  accepts_nested_attributes_for :user  
end

和表单视图代码:

<%= form_for(@team) do |f| %>
  <% if @team.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@team.errors.count, "error") %> prohibited this team from being saved:</h2>

      <ul>
      <% @team.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :memberships do |m| %>
    <div class="field">
      <%= m.label :memberships_name %><br>
      <%= m.text_field :name %>
    </div>

    <%= m.fields_for :user do |u| %>
      <div class="field">
        <%= u.label :user_name %><br>
        <%= u.text_field :name %>
      </div>    
    <% end %>
  <% end %>


  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

另外,请确保您在控制器中更改此设置:

# GET /teams/new
def new
  @team = Team.new
  3.times do # number of members you need to generate!
    @team.memberships.build{ |m| m.build_user } 
  end
end

# GET /teams/1/edit
def edit
end

# POST /teams
# POST /teams.json
def create
  @team = Team.new(team_params)

  respond_to do |format|
    if @team.save
      format.html { redirect_to @team, notice: 'Team was successfully created.' }
      format.json { render action: 'show', status: :created, location: @team }
    else
      format.html { render action: 'new' }
      format.json { render json: @team.errors, status: :unprocessable_entity }
    end
  end
end

private
  # Use callbacks to share common setup or constraints between actions.
  def set_team
    @team = Team.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def team_params
    params.require(:team).permit(:name, memberships_attributes: [:id, :name, user_attributes: [:id, :name]])
  end

虽然您可以在 Rails 控制台中执行此操作以进行快速代码验证:

team_params = {"name"=>"Team", "memberships_attributes"=>{"0"=>{"name"=>"Membership 1", "user_attributes"=>{"name"=>"User 1"}}, "1"=>{"name"=>"Membership 2", "user_attributes"=>{"name"=>"User 2"}}, "2"=>{"name"=>"Membership 3", "user_attributes"=>{"name"=>"User 3"}}}}

team = Team.new(team_params)
team.save
team.users
#=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, name: "User 1", email: nil, created_at: "2014-09-04 11:25:48", updated_at: "2014-09-04 11:25:48">, #<User id: 2, name: "User 2", email: nil, created_at: "2014-09-04 11:25:48", updated_at: "2014-09-04 11:25:48">, #<User id: 3, name: "User 3", email: nil, created_at: "2014-09-04 11:25:48", updated_at: "2014-09-04 11:25:48">]>

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    相关资源
    最近更新 更多