ruby-on-rails – 使用强参数Rails创建和更新嵌套模型

这是我的3个型号.

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

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

Membership
    belongs_to :team
    belongs_to :user

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

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

Team控制器的强参数

#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

对于表单,我只有:

>名称(文本字段)
>部门(组合框)
> leader(组合框,根据所选部门生成选项,提交为所选用户用户ID)
>成员(组合框,多个,根据所选部门生成的选项,提交为所选用户用户ID数组)

我可以成功创建一个团队,同时在我的创建上传递验证(包括团队和成员模型).但是,我不知道如何更新团队,因为如果我使用@ team.users.clear然后简单地从create做同样的事情(我知道,这样做有点愚蠢),它会验证,但是无论是否有错误,它都会保存它.

表格代码

<%= 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,{include_blank: true},{id: "team_members",multiple: :multiple,data: {member_ids: pre_select(:members)}}%>

<% end %>

表格注意事项:

>此表单适用于空白和填充表单.
>:成员字段已启用select2.

所以我的问题是:

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

一些选择导致解决方

选项#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方法.但似乎成员覆盖了领导者setter,因为我对两个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

解决方法

因为,领导者和成员在你的场景中并没有那么不同.您可以将模型和视图表单更改为以下内容

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

class User < ActiveRecord::Base
  has_many :memberships
  has_many :teams,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",#<User id: 3,name: "User 3",updated_at: "2014-09-04 11:25:48">]>

我希望它有所帮助.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...