Rails:first_or_create不保存

时间:2015-08-19 20:21:00

标签: ruby-on-rails

我的应用程序的目标是仅显示包含现有数据的表单页面或新表单的空白表单。我通过使用在创建用户时创建空白记录的回调来完成此操作。

用户模型:

before_create :build_health_profile

但是,如果由于某种原因用户“health_profile”被销毁或不存在,它会破坏我的整个应用程序:

“nil的未定义方法`health_profile”:NilClass“

有人向我提到,“first_or_create”方法可以通过显示新表单或查找现有表单来解决这个问题,但我无法通过它来保存字段。它保存了我的保存警报指向我的根目录,但实际上没有任何保存。

控制器:

class HealthProfilesController < ApplicationController

  def new
    @health_profile = current_user.build_health_profile
  end

  def create
    @health_profile = HealthProfile.where(user_id: current_user).first_or_create(health_profile_params)
    if @health_profile.save
      flash[:success] = "Health profile saved."
      redirect_to root_path
    else
      render 'new'
    end
  end

  private

  def health_profile_params
    params.require(:health_profile).permit(
       :age,
       :weight,
       :height,
       :gender
    )
  end
end

我已经看到了我可以在“first_or_create”中使用块的地方,但没有运气可以让它工作。

查看:

<%= link_to "Health Profile", new_health_profile_path %>

型号:

class User < ActiveRecord::Base
  has_one :health_profile, dependent: :destroy
end

class HealthProfile < ActiveRecord::Base
   belongs_to :user
end

3 个答案:

答案 0 :(得分:4)

如果您使用first_or_create,则会在记录中调用save方法作为其一部分,并尝试将其保存在数据库中。如果无法保存记录,则回滚事务。所以,你想在first_or_initialize使用{{3}},就像new一样,不会立即将记录保存在数据库中。它只是加载数据。因此,您可以在代码的下一行调用save

所以,在您的代码中,您拥有:

 @health_profile = HealthProfile.where(user_id: current_user).first_or_create(health_profile_params)

此处您无法控制save部分,first_or_create方法已经完成了这项工作。

因此,您实际上只想使用first_or_initialize加载对象(尚未保存):

 @health_profile = HealthProfile.where(user_id: current_user).first_or_initialize(health_profile_params)

然后,在下一行中,您可以调用save,根据它的返回值,您可以做出决定:

if @health_profile.save
  # do stuff if successfully saved health_profile
else
 # otherwise
 render 'new'
end

答案 1 :(得分:1)

因为您有@health_profile.save

您应该将first_or_create更改为first_or_initialize

first_or_create会立即触发save,而first_or_initialize只会将值分配给新记录或已存在记录(如果记录已存在)

答案 2 :(得分:0)

通过调整新操作返回表单时,我能够解决记录重置自身的问题。这是每个人的帮助。

def new
  @health_profile = current_user.health_profile || HealthProfile.new
end

def create
   @health_profile = HealthProfile.where(user_id: current_user).first_or_initialize(health_profile_params)
   if @health_profile.save
     flash[:success] = "Health profile saved."
       redirect_to root_path
   else
       render 'new'
   end
end