【问题标题】:Rails, submitting array to postgresRails,将数组提交给postgres
【发布时间】:2020-08-13 23:43:45
【问题描述】:

我有一个 Rails API,我试图将一个数字数组传递给我的 postgres 数据库,但我不能:我发送一个包含两个值的数组,它接受一个只有第一个值的数组。

我有 2 个模型,ItinaryEvent,其中:

class Event 
  belongs_to: itinary
  accepts_nested_attributes_for :itinary

class Itinary
   has_many: events

我使用 Postgres 和一个 React 前端以及带有 Postgres 的 Rails API。如果类型为decimal,我声明了一个array 类型的列:

  • Rails Postgres 架构:我将DECIMAL 设置为类型:
create_table "itinaries", force: :cascade do |t|
    ...
    t.decimal "start_gps", default: [], array: true
  • Rails EventsController:没什么花哨的,来自Event控制器,create方法是:Event.new(event_params),strong params方法也比较简单:
def event_params
   params.require(:event).permit( 
      ...,
      itinary_attributes: [...,  start_gps: [] ],
      ...
   )
end

我检查了Event.first.itinary.start_gps.class 返回Array。我可以用Itinary.create!(..., start_gps:[45,1]) 播种(值是数字)。

  • React 表单:数据在 React 的 FormData 中发送,我相信我使用了正确的 Rails 命名约定:
const fdata = new FormData()
fdata.append("events[itinary_attributes][start]", itinary.start)
fdata.append("events[itinary_attributes][start_gps][]", itinary.start_gps)
...

所以我的 POST 请求的标头包含:

event[itinary_attributes][start_gps][]: 45.1936513315257,0.6646728515625

提交时,我得到了几乎所需的参数,但数组中的值被引用:

 Parameters: 
{"event"=>{
   "itinary_attributes"=>{
       "date"=>"2020-08-16",
       "start"=>"Paris FRA",
       "start_gps"=>["48.85011347181819,2.3353889957070355"], << one value ?
       }
   }
}

这样我在 Postgres 触发时只得到第一个值:

 Itinary Create (2.5ms)  
INSERT INTO "itinaries" ...
  ["start_gps", "{48.85011347181819}"], <<<<< ONLY FIRST
                   ^^
]
  • 如果我将 t.stringt.text 设置为架构中的数据类型,Postgres 会触发:
Itinary Create (2.5ms) 
 ["start_gps", "{\"45.18978009667531,0.6811523437500001\"}"]]

所以Event.last.itinary.start_gps.length 返回 1,一个连接的值:

start_gps: Array(1)
=> "45.158800738352106,1.5051269531250002"

我什至尝试从 React 提交一个字符串数组,但没有成功。从哪儿开始?我相信这是非常经典的东西。看起来 Rails 或 Postgres 无法读取分隔数组中两个值的逗号 ','。

【问题讨论】:

    标签: ruby-on-rails postgresql strong-parameters


    【解决方案1】:

    如果有任何兴趣,可以“手动”解决这个问题:为了将一组数字保存到一个数组字段中,我拆分了接收到的参数。这是不能令人满意的,因为如此简单的工作需要如此多的手势。我还是不明白怎么回事。

    一种解决方案是在控制器中添加:

    if params[:event][:itinary_attributes][:start_gps]
          params[:event][:itinary_attributes][:start_gps] = params[:event][:itinary_attributes][:start_gps][0].split(',')
    end
    
    event_params = params.require(:event).permit( 
       ...,
       itinary_attributes: [...,:start, start_gps: [], end_gps: []],  
       ) 
    Event.new(event_params)
    ...
    

    【讨论】:

    • 在您发表评论后,我编辑了我的答案。它应该为您提供参数拆分。
    • 是的,谢谢,你写的,我可以通过这种方式追加到数组中。在这种情况下,我事先知道我只需要数组中的两个条目。但是在我的应用程序的其他地方,我在数组中追加了未知数量的值,因此如果我从前端执行此操作,或者将参数与后端拆分,我需要遍历计算的长度以编程方式追加。我在传递数组时仍然找不到任何东西。
    【解决方案2】:

    你可能想试试这个:

    const fdata = new FormData()
    fdata.append("events[itinary_attributes][start]", itinary.start)
    fdata.append("events[itinary_attributes][start_gps][]", itinary.start_gps[0])
    fdata.append("events[itinary_attributes][start_gps][]", itinary.start_gps[1])
    

    这应该让你

    {"event"=>{
      "itinary_attributes"=>{
        "date"=>"2020-08-16",
        "start"=>"Paris FRA",
        "start_gps"=>["48.85011347181819", "2.3353889957070355"] <-- Two values in an array
       }
    

    【讨论】:

    • 这将以"start_gps"=&gt;[{"0"=&gt;"47.2", "1"=&gt;"0.45"} 的形式创建参数,强参数start_gps: [] 不允许,因此我需要声明这些键。但是,应该有一种方法可以在不知道数组长度的情况下使用数组,不是吗?我仍然不明白有什么问题。
    猜你喜欢
    • 2015-09-13
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 2015-03-05
    • 1970-01-01
    相关资源
    最近更新 更多