ruby-on-rails - 在保存之前验证必须通过另一个模型运行的 Rails 表单字段
问题描述
我有一个处理航班的 Ruby on Rails(Ruby 2.5.1,Rails 5.1)应用程序;除其他外,它有一个Flight
模型和一个Airline
模型,带有Flight belongs_to :airline
和Airline has_many :flights
。Airline
有一iata_code
列包含两个字母的 IATA 航空公司代码(即AA
, UA
, WN
, F9
)。
对于航班输入表单,我希望用户能够输入任意 IATA 代码,而不是从下拉列表中选择航空公司。如果用户输入的 IATA 代码与Airline
表中的记录匹配,则该Flight.airline_id
列应设置为该航空公司的 ID。如果 IATA 代码与我数据库中的航空公司不匹配,则应使用提供的 IATA 代码创建航空公司,并将新航空公司的 ID 分配给Flight.airline_id
.
我目前通过在我的添加/编辑航班表单中有一个航空公司 IATA 代码字段来实现此功能(请注意,表单字段被命名为:airline_iata
而不是:airline_id
):
<%= f.label :airline_iata, "Airline code" %>
<%= f.text_field :airline_iata, class: "form-control code airline-iata", maxlength: 2, placeholder: 'AA' %>
然后,在我的航班控制器create
和update
操作中,我尝试在保存航班之前查找航空公司,并设置airline_id
参数(create
如下所示,但update
类似):
def create
params[:flight][:airline_id] = Airline.find_or_create_by!(:iata_code => params[:flight][:airline_iata].upcase).id
@flight = current_traveler.flights.build(flight_params)
if @flight.save
redirect_to event_path(current_traveler.event)
else
render "new"
end
end
这种方法对我有用,除了我无法弄清楚如何从航班表格中对航空公司 IATA 代码字段进行验证。Airline 模型会验证代码 ( presence: true, length: { is: 2 }, uniqueness: { case_sensitive: false }
),因此如果用户输入了无效的 IATA 代码,则 Airline 创建将失败,因此 Flight 创建将失败。但是,我不会在 Flight 表单上看到通常的验证错误(例如错误消息、突出显示错误的表单字段),因为 Flight 的问题是airline_id
(不直接在 Flight 表单上)不存在,而不是航班表格中airline_iata
的内容无效。
如何设置它,以便在提交之前必须与 Airport 模型交互的表单字段可以在 Flight 表单字段上运行 Airport 模型的验证,并相应地返回表单验证错误?
解决方案
您可以尝试使用嵌套表单属性并添加 before_validation 钩子,它将覆盖关联:
<%= f.fields_for :airline do |airline_form| %>
<%= airline_form.label :iata_code, "Airline code" %>
<%= airline_form.text_field :iata_code %>
<% end %>
在 flight.rb 你应该有
accept_nested_attributes_for :airline
before_validation :check_existing_airline, on: :create
def check_existing_airline
if airline.new_record? && existing_airline = Airline.find_by(iata_code: airline.iata_code)
self.airline = exisitng_airline
end
end
推荐阅读
- c# - Azure表存储(Partition key row key),如何在同一个partition和不同rowKey对应的地方插入多个实体?
- fortran - 如何在 Fortran 中将字符串拆分为字符?
- android - 颤振:输入“未来”
' 不是类型 'Uint8List' 的子类型 - typescript - webdriver 删除 URL 中哈希标记 (#) 后的参数
- python - 如何遍历目录中的图像?
- amazon-web-services - 为什么我的 AWS Lambda 在部署时被标记为太大?
- javascript - × TypeError: Object is not iterable (cannot read property Symbol(Symbol.iterator))
- git - 私有 git 存储库中的 Terraform 模块
- sql - 源表有主键,我是否需要在目标表中创建
- c++ - 使用 cpp-httplib 发出 HTTPS 请求