Rails 4 个嵌套表单 belongs_to 存在保存问题
Rails 4 nested form with belongs_to problems saving
我正在开发一个新的 Rails 4 应用程序,并且很难让所有部分正确地协同工作。我有一个模型(样本)与另一个模型(lat_long)有 belongs_to 关联,我正在尝试从样本视图(编辑默认生成的视图)对这两个模型进行 CRUD 操作。问题是 lat_long 可以为空;如果不是,一切正常,但当它在模型中进行验证时,所以我认为它试图保存一个空白 lat_long 而不是将其设置为 nil。更新和编辑是问题。
以下是代码中的相关部分:
型号:
class Sample < ActiveRecord::Base
belongs_to :lat_long
accepts_nested_attributes_for :lat_long
end
class LatLong < ActiveRecord::Base
validates_each :west_longitude do |record, attr, value|
record.errors.add attr, "must be within range." if (value < 110.0 or value > 115.0)
end
validates_each :north_latitude do |record, attr, value|
record.errors.add attr, "must be within range." if (value < 38.0 or value > 42.0)
end
end
samples/_form.html.erb 用于编辑和新建:
<%= form_for(@sample) do |f| %>
<%= f.fields_for :lat_long do |g| %>
<div class="field">
<%= g.label :north_latitude %><br>
<%= g.text_field :north_latitude %>
</div>
<div class="field">
<%= g.label :west_longitude %><br>
<%= g.text_field :west_longitude %>
</div>
<% end %>
<% end %>
samples_controller.rb:
class SamplesController < ApplicationController
# GET /samples/new
def new
@sample = Sample.new
@sample.build_lat_long
@sample.build_trap
end
# GET /samples/1/edit
def edit
@sample.lat_long || @sample.build_lat_long
@sample.trap || @sample.build_trap
end
# POST /samples
# POST /samples.json
def create
@sample = Sample.new(sample_params)
puts sample_params
respond_to do |format|
if @sample.save
format.html { redirect_to @sample, notice: 'Sample was successfully created.' }
format.json { render :show, status: :created, location: @sample }
else
format.html { render :new }
format.json { render json: @sample.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /samples/1
# PATCH/PUT /samples/1.json
def update
respond_to do |format|
if @sample.update(sample_params)
format.html { redirect_to @sample, notice: 'Sample was successfully updated.' }
format.json { render :show, status: :ok, location: @sample }
else
format.html { render :edit }
format.json { render json: @sample.errors, status: :unprocessable_entity }
end
end
end
def sample_params
params.require(:sample).permit(...,
lat_long_attributes: [:id,
:west_longitude, :north_latitude])
end
end
我当然可以在更新前检查控制器,但这样做正确吗?它 "feels" 好像应该有一种方法可以让 Rails 处理这个问题,但是查看大量 Whosebug 问题和文档并没有给我任何想法。大多数示例使用 has_one 或 has_many,所以我不知道这是不是问题所在?根据 this question 的说法,belongs_to 与 accepts_nested_attributes_for 一起使用是新的,所以也许它只是没有为此设置。
我想知道这种情况的最佳实践是什么,最"Railsy"要做的事情。哦,我想我已经包含了所有相关的代码,但是如果您还需要看什么,请告诉我。
我会这样做:
class Sample < ActiveRecord::Base
belongs_to :lat_long
accepts_nested_attributes_for :lat_long, reject_if: proc { |attributes| attributes['west_longitude'].blank? && attributes['north_latitude'].blank? }
end
class LatLong < ActiveRecord::Base
validates :west_longitude, numericality: { greater_than_or_equal_to: 110,
less_than_or_equal_to: 115,
message: "must be within range" },
allow_nil: true
validates :north_latitude, numericality: { greater_than_or_equal_to: 38,
less_than_or_equal_to: 42,
message: "must be within range" },
allow_nil: true
end
我正在开发一个新的 Rails 4 应用程序,并且很难让所有部分正确地协同工作。我有一个模型(样本)与另一个模型(lat_long)有 belongs_to 关联,我正在尝试从样本视图(编辑默认生成的视图)对这两个模型进行 CRUD 操作。问题是 lat_long 可以为空;如果不是,一切正常,但当它在模型中进行验证时,所以我认为它试图保存一个空白 lat_long 而不是将其设置为 nil。更新和编辑是问题。
以下是代码中的相关部分:
型号:
class Sample < ActiveRecord::Base
belongs_to :lat_long
accepts_nested_attributes_for :lat_long
end
class LatLong < ActiveRecord::Base
validates_each :west_longitude do |record, attr, value|
record.errors.add attr, "must be within range." if (value < 110.0 or value > 115.0)
end
validates_each :north_latitude do |record, attr, value|
record.errors.add attr, "must be within range." if (value < 38.0 or value > 42.0)
end
end
samples/_form.html.erb 用于编辑和新建:
<%= form_for(@sample) do |f| %>
<%= f.fields_for :lat_long do |g| %>
<div class="field">
<%= g.label :north_latitude %><br>
<%= g.text_field :north_latitude %>
</div>
<div class="field">
<%= g.label :west_longitude %><br>
<%= g.text_field :west_longitude %>
</div>
<% end %>
<% end %>
samples_controller.rb:
class SamplesController < ApplicationController
# GET /samples/new
def new
@sample = Sample.new
@sample.build_lat_long
@sample.build_trap
end
# GET /samples/1/edit
def edit
@sample.lat_long || @sample.build_lat_long
@sample.trap || @sample.build_trap
end
# POST /samples
# POST /samples.json
def create
@sample = Sample.new(sample_params)
puts sample_params
respond_to do |format|
if @sample.save
format.html { redirect_to @sample, notice: 'Sample was successfully created.' }
format.json { render :show, status: :created, location: @sample }
else
format.html { render :new }
format.json { render json: @sample.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /samples/1
# PATCH/PUT /samples/1.json
def update
respond_to do |format|
if @sample.update(sample_params)
format.html { redirect_to @sample, notice: 'Sample was successfully updated.' }
format.json { render :show, status: :ok, location: @sample }
else
format.html { render :edit }
format.json { render json: @sample.errors, status: :unprocessable_entity }
end
end
end
def sample_params
params.require(:sample).permit(...,
lat_long_attributes: [:id,
:west_longitude, :north_latitude])
end
end
我当然可以在更新前检查控制器,但这样做正确吗?它 "feels" 好像应该有一种方法可以让 Rails 处理这个问题,但是查看大量 Whosebug 问题和文档并没有给我任何想法。大多数示例使用 has_one 或 has_many,所以我不知道这是不是问题所在?根据 this question 的说法,belongs_to 与 accepts_nested_attributes_for 一起使用是新的,所以也许它只是没有为此设置。
我想知道这种情况的最佳实践是什么,最"Railsy"要做的事情。哦,我想我已经包含了所有相关的代码,但是如果您还需要看什么,请告诉我。
我会这样做:
class Sample < ActiveRecord::Base
belongs_to :lat_long
accepts_nested_attributes_for :lat_long, reject_if: proc { |attributes| attributes['west_longitude'].blank? && attributes['north_latitude'].blank? }
end
class LatLong < ActiveRecord::Base
validates :west_longitude, numericality: { greater_than_or_equal_to: 110,
less_than_or_equal_to: 115,
message: "must be within range" },
allow_nil: true
validates :north_latitude, numericality: { greater_than_or_equal_to: 38,
less_than_or_equal_to: 42,
message: "must be within range" },
allow_nil: true
end