我的应用程序的目标是仅显示包含现有数据的表单页面或新表单的空白表单。我通过使用在创建用户时创建空白记录的回调来完成此操作。
用户模型:
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
答案 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