微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Ruby On Rails PG 数据库问题使用嵌套表单,表实体具有无表模型关系“有很多”

如何解决Ruby On Rails PG 数据库问题使用嵌套表单,表实体具有无表模型关系“有很多”

我正在处理的任务的主要目的是为管理员创建一个包含多个时间范围的表单,以便我可以将这些时间范围作为 jsonb 属性保存在我的数据库中。我可以根据需要添加任意数量的时间范围。前端动态已经完成,但我在后端和我想要获得的参数方面挣扎了很多。

我想从我的简单表单中获得的参数应该如下所示:

admin: {first_name,last_name,age,time_ranges: [{start_time,end_time},{start_time,end_time}...]}

我已经阅读了很多关于嵌套表单的内容,但我无法实现我想要的。我尝试为 Dateranges 创建一个无表模型,因此在我的 SuperAdmin 模型(在我的数据库中有一个表)中,我可以使用 has_many: time_ranges 和 accepts_nested_attributes_for: date_ranges。

class Admin < ApplicationRecord
  has_many :time_ranges
  accepts_nested_attributes_for :time_ranges
end

class TimeRange < ApplicationRecord
    include ActiveModel::Model
    include ActiveModel::Attributes

    attribute :end_time
    attribute :start_time
  
    attr_accessor :start_time,:end_time
    belongs_to :admin
  
    def initialize(attributes = {})
      attributes.each do |name,value|
        send("#{name}=",value)
      end
    end
  
    def persisted?
      false
    end
end

在我的 admin_controller 中,我的参数中有这个:

    def admin_params
        params.require(:admin).permit(:first_name,:last_name,:age,time_ranges_attributes: [:start_date,:end_date])
    end

我在视图中使用简单的表单,所以我的前端看起来像这样:

<%= simple_form_for @admin,url: admin_path(@admin),method: :put do |f|%>
      <tr>
        <td>Name</td>
        <td><%= f.input :first_name %></td>
        <td>Last Name</td>
        <td><%= f.input :last_name %></td>
      </tr>
      <%= f.simple_fields_for :time_ranges do |p|%>
      <tr>
        <td>
          <p class='ml-1'>Start</p>
          <%= p.input :start_time,as: :time,ignore_date: true %>
        </td>
        <td>
          <p class='ml-1'>End</p>
          <%= p.input :end_time,ignore_date: true %>
        </td>
        <td>
        </td>
      </tr>
      <% end %>

--------------...I Could add as many simple_fields_for as I want (front-end logic using StimulusJS) ---------------------------------------------

  <%= f.button :submit,class: 'button is-info' %>
<% end %>

我发现的这种方式可以给我想要的结果,但是我尝试访问我的视图时立即收到以下错误

PG::UndefinedTable: ERROR:  relation "time_ranges" does not exist
LINE 1: SELECT "time_ranges".* FROM "time_ranges" WHERE "time_ranges...

我知道这是因为我的数据库中不存在 time_range 实体,但我希望得到您的帮助来解决此问题,或者如果您给我另一个获取参数的解决方案,我将不胜感激我想要。我使用的是 Rails 5.2。

解决方法

has_many 和嵌套属性用于关联。这不是一个关联,它只是一个包含 Rails 将序列化和反序列化的字符串的列。这就是 Rails 对 JSONB 的全部了解。

您传递的是一个数组参数,而不是嵌套的属性。

def admin_params
  params.require(:admin).permit(:first_name,:last_name,:age,time_ranges: [])
end

由管理员来验证 time_ranges 是否包含正确的对象。

您的表单将接受名称为 admin[time_ranges][][start_date]admin[time_ranges][][end_date] 的输入。见Parameter Naming Conventions


由于 Rails 不知道 JSONB 关联,因此需要做更多的工作。这可以更简单地与具有单个 tztsrange or daterange column 的真实表进行常规关联(不清楚您是在存储时间还是日期)。

create_table :admin_availability do
  t.belongs_to :admin
  t.tztsrange :availability,null: false
end

class AdminAvailability < ApplicationRecord
  belongs_to :admin
end

class Admin < ApplicationRecord
  has_many :admin_availabilities
  accepts_nested_attributes_for :admin_availability
end

现在嵌套属性机制将起作用。您可能仍然需要将 start_time/end_time 参数转换为单个 Range 对象。向控制器添加便利访问器可能更简单。

class AdminAvailability < ApplicationRecord
  belongs_to :admin

  def start_time
    availability.begin
  end

  def start_time=(start)
    self.availability = Range.new(start,end_time)
  end

  def end_time
    availability.end
  end

  def end_time=(end)
    self.availability = Range.new(start_time,end)
  end
end

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。