Rails嵌套的连接表属性将不会被保存

时间:2014-05-01 11:03:10

标签: ruby-on-rails nested-attributes

不会保存连接模型的嵌套属性。似乎缺少关系id。验证字段时添加以下错误消息:

* Assigned projects user can't be blank
* Assigned projects project can't be blank

提交的参数看起来像这样(<%= debug(params)%>)

--- !map:ActionController::Parameters 
utf8: "\xE2\x9C\x93"
authenticity_token: HrF1NHrKNTdMMFwOvbYFjhJE1ltlKbuz2nsfBYYBswg=
project: !map:ActionController::Parameters 
  name: Peter Pan
  assigned_projects_attributes: !map:ActiveSupport::HashWithIndifferentAccess 
    "0": !map:ActiveSupport::HashWithIndifferentAccess 
      position: Group Leader
  currency: " Neverland Dollars"
commit: Add Project
action: create
controller: projects

我有3个型号,如下:

class User < ActiveRecord::Base
  has_many :assigned_projects
  has_many :projects, :through => :assigned_projects
  has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end

class AssignedProject < ActiveRecord::Base
    belongs_to :user,    class_name: "User"
    belongs_to :project, class_name: "Project"

    attr_accessible :project_id, :user_id, :position, :project_attributes
    accepts_nested_attributes_for :project

    validates :user_id,     presence: true
    validates :project_id,  presence: true
    validates :position,    presence: true
end

class Project < ActiveRecord::Base
  belongs_to :user
  has_many :assigned_projects
  has_many :users, :through => :assigned_projects
  belongs_to :creator, :class_name => "User", :foreign_key => :creator_id

  attr_accessible :name, :creator_id, :currency :assigned_projects_attributes
  accepts_nested_attributes_for :assigned_projects

  validates :name, presence: true, length: { minimum: 3, maximum: 100 }
  validates :currency, presence: true, length: { minimum: 1, maximum: 5 }
  validates :creator_id, presence: true
end

因此每个用户都可以创建一个项目。他可以通过连接模型将任何用户添加到项目中。 每个项目属于一个用户分配。创建者和has_many用户通过assigned_projects

我想给项目的每个用户一个“位置”,该位置应该保存在连接模型中:assigned_project:position

Project控件看起来像这样:

class ProjectsController < ApplicationController

    def new
        @project = Project.new
        @project.assigned_projects.build(user_id: current_user)
    end

    def create
        @project = current_user.assigned_projects.build.build_project(params[:project])
        @project.creator = current_user

        if @project.save
            redirect_to current_user
        else
            render 'new'
        end
    end
end

并且project / new.html.erb表单看起来像这样:

<%= form_for( @project ) do |f| %>

    <%= render 'shared/error_messages', object: f.object %>

    <%= f.label :name %>
    <%= f.text_field :name %>

    <%= f.fields_for :assigned_projects do |ff| %>
        <%= ff.label :position %>
        <%= ff.text_field :position%>
    <% end %>

    <%= f.label :currency %>
    <%= f.text_field :currency %>

    <%= f.submit "Add Project", class: "" %>                    
<% end %>

更新:当前控制器&amp;图

def create
    @project = Project.new(params[:project])
    if @project.save
        redirect_to current_user
    else
        render 'new'
    end
end

<%= form_for( @project ) do |f| %>

    <%= render 'shared/error_messages', object: f.object %>

    <%= f.label :name %>
    <%= f.text_field :name %>

    <%= f.hidden_field :creator_id, value: current_user.id %>

    <%= f.fields_for :assigned_projects, @project.assigned_projects do |ff| %>
        <%= ff.label :position %>
        <%= ff.text_field :position%>
    <% end %>

    <%= f.label :currency %>
    <%= f.text_field :currency %>

    <%= f.submit "Add Project", class: "" %>
<% end %>                   

3 个答案:

答案 0 :(得分:0)

查看:

我认为您需要将@project.assigned_projects操作中构建的对象集合new传递给fields_for

<%= render 'shared/error_messages', object: f.object %>

<%= f.label :name %>
<%= f.text_field :name %>

<%= f.fields_for :assigned_projects, @project.assigned_projects do |ff| %>
    <%= ff.label :position %>
    <%= ff.text_field :position%>
<% end %>

<%= f.label :currency %>
<%= f.text_field :currency %>

<%= f.submit "Add Project", class: "" %>                    

控制器:

如果我理解create操作中的第一行,我认为您尝试重新构建项目assigned_projects以便标记creator属性!!

相反,你可以删除这一行并在嵌套for中放入一个隐藏字段,例如:

<%= ff.hidden_field :creator, current_user %>

所以你的控制器现在看起来非常基本:

def create
  @project = Project.new(params[:prject])
  if @project.save #nested objects will be saved automatically
    redirect_to current_user
  else
    render 'new'
  end
end

答案 1 :(得分:0)

build_project方法有什么作用? 我认为在你的控制器中你应该只有build,而不是build.build_project,所以这样:

@project = current_user.assigned_projects.build(params[:project])

如果build_project是用于创建参数的方法,那么

 @project = current_user.assigned_projects.build(project_params)

对于rails 4,你需要这样的东西:

def project_params
    params.require(:project).permit(:your_params)
end

对于rails 3,我认为你需要添加

attr_accessible :param1, :param2 
项目模型中的

表示您要设置的参数。

答案 2 :(得分:0)

通过删除连接表中的project_id和user_id的验证来解决问题&#34; AssignedProject&#34;

所以连接模型看起来像这样:

# Join Model AssignedProject
class AssignedProject < ActiveRecord::Base
    belongs_to :user#,    class_name: "User"
    belongs_to :project#, class_name: "Project"

    attr_accessible :project_id, :user_id, :position, :project, :project_attributes
    accepts_nested_attributes_for :project

    validates :position,  presence: { message: " can't be blank." }
end

New和Create方法看起来像这样:

# Projects Controller
class ProjectsController < ApplicationController
    def new
        @project = Project.new
        @project.assigned_projects.build(user_id: current_user)
    end

    def create
        @project = Project.new(params[:project])

        if @project.save
            @project.assigned_projects.create(user_id: current_user)
            redirect_to current_user
        else
            render 'new'
        end
    end
end

新方法视图中的表单如下所示:

<%= form_for( @project ) do |f| %>

    <%= render 'shared/error_messages', object: f.object %>

    <%= f.label :name %>
    <%= f.text_field :name %>

    <%= f.hidden_field :creator_id, value: current_user.id %>

    <%= f.fields_for :assigned_projects, @project.assigned_projects do |ff| %>

        <%= ff.hidden_field :project_id, value: @project %>
        <%= ff.hidden_field :user_id, value: current_user.id %>

        <%= ff.label :position %>
        <%= ff.text_field :position%>
    <% end %>

    <%= f.label :currency %>
    <%= f.text_field :currency %>

    <%= f.submit "Add Project", class: "" %>                    
<% end %>