has_one 嵌套属性未保存 [英] has_one nested attributes not saving

查看:38
本文介绍了has_one 嵌套属性未保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个模型 Project 和 ProjectPipeline.

I have two models Project and ProjectPipeline.

我想创建一个项目表单,该表单也包含来自 ProjectPipeline 模型的字段.我已经成功创建了表单,但是当我点击保存时,这些值没有存储在数据库中.

I want to create a Project form that also has fields from the ProjectPipeline model. I have created the form successfully but when I hit save the values aren't stored on the database.

project.rb

class Project < ActiveRecord::Base

  has_one :project_pipeline

  accepts_nested_attributes_for :project_pipeline

  self.primary_key = :project_id
end

projectpipeline.rb

class ProjectPipeline < ActiveRecord::Base

  belongs_to :project, autosave: :true

  validates_uniqueness_of :project_id

end

我并不总是想要一个项目管道,而是在基于用户查看项目的正确条件下.我希望构建项目管道字段,但仅在用户选择保存/填充它们时才保存.

I don't always want a project pipeline but under the right conditions based on a user viewing a project. I want the project pipeline fields to be built, but only saved if the user chooses to save/populate them.

因此,当显示项目时,我使用 project_id: from params[:id] 构建了一个临时项目管道(不确定我是否真的需要这样做).然后当项目被保存时,我使用 create_attributes.但如果它已经创建或构建,我只想让 has_one 和 Beings_to 关联启动,然后使用 update_attributes.

So when the project is shown I build a temporary project pipeline using the project_id: from params[:id] (not sure if I really need to do this). Then when the project is saved I use the create_attributes. But if it has already been created or built I just want to let the has_one and belongs_to association kick in and then use update_attributes.

我的问题是当我尝试保存时,如果我使用 params[:project_pipeline] 会遇到禁止属性"错误,或者如果我使用 project_params 则根本没有保存任何内容.我已经检查并重新检查了我的所有字段都在 project_params 中,甚至尝试使用 project_pipeline_params 但感觉不对.

My issue is when I am trying to save, I am either hitting a 'Forbidden Attribute' error if I use params[:project_pipeline] or having nothing saved at all if I used project_params. I have checked and rechecked all my fields are in project_params and even tried using a project_pipeline_params but that didn't feel right.

这让我发疯,我需要睡觉.

It is driving me nuts and I need to sleep.

projects_controller.rb

def show
  @project = Project.find(params[:id])
  if @project.project_pipeline
  else
    @project.build_project_pipeline(project_id: params[:id])
  end
  autopopulate
end



def update
    @project = Project.find(params[:id])
    if @project.project_pipeline
    else
      @project.build_project_pipeline(project_id: params[:id], project_type: params[:project_pipeline][:project_type], project_stage: params[:project_pipeline][:project_stage])
    end
    if @project.update_attributes(project_params)
      flash[:success] = "Project Updated"
      redirect_to [@project]
    else
      render 'edit'
    end
  end


def project_params
  params.require(:project).permit(:user_id, project_pipeline_attributes:[:project_id,:project_type,:project_stage,
      :product_volume,:product_value,:project_status,:outcome, :_destroy])
end

show.html.haml

    - provide(:title, "Show Project")
%h1= @project.project_title
= simple_form_for(@project) do |f|
  = f.input  :id, :as => :hidden, :value => @project, :readonly => true  
  = f.input :user_id, label: 'Assigned to Account Manager', :collection => @account_managers, :label_method => lambda { |r| "#{r.first_name} #{r.last_name}" }
  = f.input :project_id, :readonly => true
  = f.input :status, :readonly => true
  = f.input :project_stage, :readonly => true

  - if @project.project_codename = "project pipeline"
    = simple_fields_for @project.project_pipeline do |i|
      %h2 Project Pipeline
      - if @project.user_id == current_user.id
        = i.input :project_volume, label: 'Project Status', collection: @project_status
        = i.input :project_value, label: 'Project Status', collection: @project_status
        = i.input :project_status, label: 'Project Status', collection: @project_status
      = i.input :outcome, label: 'Outcome', collection: @outcome


    = f.submit 'Save'

如果你做到了这一点,我真诚地感谢你.

If you've gotten this far I sincerely thank you.

推荐答案

解决方案

您需要在这里更改一些内容.首先:

Solution

You need to change few things here. Firstly:

= simple_fields_for @project.project_pipeline do |i|

当您传递对象时,rails 不知道它与父对象相关联,因此将创建一个名为 project[project_pipeline] 的字段,而不是 project[project_pipeline_attributes].相反,您需要传递关联名称并在表单构建器上调用此方法:

When you pass the object, rails have no idea it is to be associated with the parent object and as a result will create a field named project[project_pipeline] instead of project[project_pipeline_attributes]. Instead you need to pass the association name and call this method on the form builder:

= f.simple_fields_for :project_pipeline do |i|

这将检查您是否定义了 project_pipeline_attributes= 方法(使用 accept_nested_attributes_for` 并将其视为关联.然后在您的控制器中将您的显示操作更改为:

This will check find out that you have defined project_pipeline_attributes= method (using accept_nested_attributes_for` and will treat it as association. Then in your controller change your show action to:

def update
  @project = Project.find(params[:id])
  @project.assign_attributes(project_params)
  if @project.save
    flash[:success] = "Project Updated"
    redirect_to @project
  else
    render 'edit'
  end
end

一切都应该有效.作为单独的说明,由于您允许嵌套参数中的 :_destroy 属性,我假设您希望能够使用嵌套属性删除记录.如果是这样,您需要将 allow_destroy: true 添加到您的 accepts_nested_attributes_for 调用中.

And all should work. As a separate note, since you are allowing :_destroy attribute in nested params, I am assuming you want to be able to remove the record using nested attributes. If so, you need to add allow_destroy: true to your accepts_nested_attributes_for call.

您可以稍微改进一下表演动作.首先,我注意到如果尚未声明任何操作,您将在每个操作中构建一个空管道.这意味着您可能应该将此逻辑移动到您的模型中:

You can improve your show action a bit. First of all, I've noticed you are building an empty pipeline in every single action if none has been declared yet. That mean that you probably should move this logic into your model:

class Project < AR::Base

  after_initalize :add_pipeline

  private

  def add_pipeline
    project_pipeline || build_project_pipeline
  end
end

您还有神秘的方法 prepopulate - 很可能它也应该是模型问题.

You also have the mysterious method prepopulate - most likely it should be model concern as well.

另一点:这个语法:

if something
else
  # do sth
end

以某种方式非常流行,并且使代码变得难以阅读.相反,请使用:

is somehow quite popular and makes the code unreadable as hell. Instead, use:

if !something
  # do something
end

或(首选)

unless something
  # do something
end

这篇关于has_one 嵌套属性未保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆