(轨道)fields_for序列化的列未填充数据

时间:2018-11-21 16:42:19

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

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

问题是:如果@order验证失败,则OrdersController会再次显示@order的错误的表单视图,但是{{ 1}}哈希。

我看到了很多破解解决方案,可以将序列化的列转换为attr_accessors。 是否存在一种方便的解决方案,用于从Rails中的序列化列填充表单字段?

这是我的代码...

order.rb

:address

new.html.erb

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

_address_fields.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 %>

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

<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>

…

谢谢!

1 个答案:

答案 0 :(得分: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)