【问题标题】:(Rails) fields_for a serialized column are not being populated with data(Rails) 序列化列的字段_未填充数据
【发布时间】:2023-03-08 13:34:01
【问题描述】:

我不会在 Rails 5.2 中通过form_with 提交@order@orderOrder 类的一个实例,它有一个用于地址字段的序列化列。地址字段由订单表单中的fields_for 填写,当将表单提交到OrdersController 时,所有字段/值都被正确传递。

问题是:如果@order 验证失败,OrdersController 会再次呈现表单视图,并显示@order 的错误,但这里的 fields_for 地址没有被 :address 哈希填充。

我看到了一些将序列化列转换为 attr_accessors 的 hacky 解决方案。 有没有方便的解决方案从 Rails 中的序列化列填充表单字段?

这是我的代码……

order.rb

class Order < ApplicationRecord
  serialize :address

  …

  validate  :address_validator

  …

  private

    def address_validator
      required_fields = [:firstname, :lastname, :line1, :city, :postal_code, :country]
      required_fields.each do |field|
        self.errors.add(:base, "Address / #{field.to_s.titleize} can't be blank") if self.address[field.to_s].blank?
      end
    end

    …
end

new.html.erb

<%= form_with model: @order, id: 'order-form', class: 'form', local: true do |f| %>
  <%= render 'shared/form_errors', object: f.object %>

  …

  <%= f.fields_for :address do |g| %>
    <%= render 'orders/address_fields', f: g %>
  <% end %>

  …

<% end %>

_address_fields.html.erb

<div class='form__row columns columns--responsive-to-small columns--with-gutter'>
  <div class='form__input form__input--mandatory'>
    <%= f.label :firstname, 'Firstname' %>
    <%= f.text_field :firstname %>
  </div>

  <div class='form__input form__input--mandatory'>
    <%= f.label :lastname, 'Lastname' %>
    <%= f.text_field :lastname %>
  </div>
</div>

<div class='form__row'>
  <div class='form__input form__input--mandatory'>
    <%= f.label :line1, 'Address (line 1)' %>
    <%= f.text_field :line1 %>
  </div>
</div>

…

提交表单后,@order 对象具有以下值(存在地址值)

(byebug) @order
#<Order id: nil, order_id: "HvMB00KS-73e1fc", …, created_at: nil, updated_at: nil, address: {"firstname"=>"Rocky", "lastname"=>"Marciano", "line1"=>"Saplestreet 123", "line2"=>"", "city"=>"Clashtown", "postal_code"=>"18726", "country"=>"Germany"}, email: "test@mail.com", products: … >

谢谢!

【问题讨论】:

  • 您是否在控制器中建立关系。 @order.build_address ?
  • address 是 Order 的属性,而不是关联的记录。它存储在Orders 表的json hash 列中。对象@order 内置在控制器中,带有来自提交表单的强参数:email, address: [:firstname, :lastname, …];可以使用@order.address['firstname'], ... 读取和设置地址属性。 fields_for 是否仅适用于嵌套模型而不适用于序列化列?
  • 我找到了一个简单的解决方案:与serialize :address 一起,我们可以使用store_accessor :address, :firstname, :lastname, … 来为地址哈希中的属性创建访问器。现在我们可以通过f.firstnamef.lastname,……直接在表单中使用属性,它们分别被填充。我在Nando Vieira's post about using jsonb in RoR 中发现了store_accessor

标签: ruby-on-rails forms serialization fields-for


【解决方案1】:

有一个方便的(没有详细记录的)解决方案,称为store_accessor,可以与序列化的属性散列一起使用,以便为其键创建访问器。感谢 Nando Vieira 的 Using PostgreSQL and jsonb with Ruby on Rails,我发现了这一点。

使用上面的示例地址哈希,我们可以定义……

class Order < ApplicationRecord
  serialize :address
  store_accessor :address, :firstname, :lastname, :postal_code, …
  …
end

设置和读取地址的属性,例如……

order = Order.new
order.firstame = 'Billy'
order.firstname
#=> "Billy"
order.address['firstname']
#=> "Billy"

在@order 的表单中,可以直接设置address 的键,并分别填充表单……

<%= form_with model: @order, local: true do |f| %>

  <%= f.label :firstname, 'Firstname' %>
  <%= f.text_field :firstname %>

  <%= f.label :lastname, 'Lastname' %>
  <%= f.text_field :lastname %>

<% end %>

在 OrdersController 中使用强参数,例如……

params.require(:order).permit(:firstname, :lastname)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 2020-03-03
    相关资源
    最近更新 更多