has_one nested attributes not saving

可紊 提交于 2019-12-04 13:34:53

Solution

You need to change few things here. Firstly:

= simple_fields_for @project.project_pipeline do |i|

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|

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

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.

Now a bit of styling:

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

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

Another point: This syntax:

if something
else
  # do sth
end

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

if !something
  # do something
end

or (preferred)

unless something
  # do something
end

I'm not sure from your description if this is the problem, but one the thing is that a update_attributes with a has_one, by default, will rebuild the children(!), so you would lose the attributes you initialised. You should provide de update_only: true option to accepts_nested_attributes_for. You can find more on this here, in the rails docs. The line would be this:

accepts_nested_attributes_for :project_pipeline, update_only: true

Considering the after_initialize, that would result in every project always having a pipeline. While that could be desirable, it isn't necessarily, depending on your domain, so I'd be a bit careful with that.

Cheers, Niels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!