更新 Rails 中的每个 Array-Object 值
Update Each Array-Object Value in Rails
基本上我想更新 Rails 5 中模型的每个 table 列。
str = "abc---def"
str.split('---').map do |a|
Foo.where(product_id:1).update_all(bar: a)
end
旧的 object 会像:
[
[0] { product_id: 1,
...,
bar: "xxx",
...
},
[1] { product_id: 1,
...,
bar: "xxx",
...
}
]
新的应该是这样的:
[
[0] { product_id: 1,
...,
bar: "abc",
...
},
[1] { product_id: 1,
...,
bar: "def",
...
}
]
但我得到的是每个 bar: "def"
。 rails 中是否有一个干净的方法来实现我想要的? update_attributes
报错。
标题名称是否正确?
首先,使用 Foo.where(id:1).update_all
更新单个记录可能有效,但不是惯用的。最好使用Foo.find_by(id: 1).update
。对于获取单个记录,我更喜欢使用 find_by
而不是 find
因为它 returns nil
而不是引发 NotFound 错误,但这是个人偏好。
其次,您使用 update_all(bar: a)
的方式会给您带来意想不到的结果。在 map
块中,returned 值成为结果数组的一部分。 update_all
没有 return 被更改的记录。它 returns 是一个整数,显示已更改的记录数。同样,update
不 return 记录。它 returns true
或 false` 取决于验证是否通过。
把这些概念结合起来,可以写成下面的代码:
str = "abc---def"
str.split('---').map do |a|
foo = Foo.find_by(id:1)
foo&.update(bar: a)
foo
end
# note that you could instead write `foo.update(bar: a)` if you
# don't want to use the safe navigation operator
或者用另一种写法来做同样的事情:
str = "abc---def"
str.split('---').map do |a|
Foo.find_by(id:1)&.tap { |foo| foo.update(bar: a) }
end
请注意,在这些示例中,我使用的 safe navigation operator Ruby 版本比 2.3
更新。它有助于防止 NoMethodError
出现在 nil 对象上,但实际上并不是必需的。
首先让我们从一些基础知识开始。
您想更新多行并且想为每一行设置不同的值。所以它不能像你正在做的那样在单个查询中完成。因此,您需要遍历 Foo
个对象并分别设置每个对象。
所以让我们假设
str = "abc---def---ghi---jkl"
tokens = str.split('---')
foos_to_update = Foo.where(product_id: 1) #Let's assume it will return 4 or lesser records. (otherwise you need to tell what do you wanna do if it returns more then `tokens`)
foos_to_update.each_with_index {|foo,i| foo.update(bar: tokens[i])}
最后一行循环遍历返回的对象并为每个对象设置 bar
值。
基本上我想更新 Rails 5 中模型的每个 table 列。
str = "abc---def"
str.split('---').map do |a|
Foo.where(product_id:1).update_all(bar: a)
end
旧的 object 会像:
[
[0] { product_id: 1,
...,
bar: "xxx",
...
},
[1] { product_id: 1,
...,
bar: "xxx",
...
}
]
新的应该是这样的:
[
[0] { product_id: 1,
...,
bar: "abc",
...
},
[1] { product_id: 1,
...,
bar: "def",
...
}
]
但我得到的是每个 bar: "def"
。 rails 中是否有一个干净的方法来实现我想要的? update_attributes
报错。
标题名称是否正确?
首先,使用 Foo.where(id:1).update_all
更新单个记录可能有效,但不是惯用的。最好使用Foo.find_by(id: 1).update
。对于获取单个记录,我更喜欢使用 find_by
而不是 find
因为它 returns nil
而不是引发 NotFound 错误,但这是个人偏好。
其次,您使用 update_all(bar: a)
的方式会给您带来意想不到的结果。在 map
块中,returned 值成为结果数组的一部分。 update_all
没有 return 被更改的记录。它 returns 是一个整数,显示已更改的记录数。同样,update
不 return 记录。它 returns true
或 false` 取决于验证是否通过。
把这些概念结合起来,可以写成下面的代码:
str = "abc---def"
str.split('---').map do |a|
foo = Foo.find_by(id:1)
foo&.update(bar: a)
foo
end
# note that you could instead write `foo.update(bar: a)` if you
# don't want to use the safe navigation operator
或者用另一种写法来做同样的事情:
str = "abc---def"
str.split('---').map do |a|
Foo.find_by(id:1)&.tap { |foo| foo.update(bar: a) }
end
请注意,在这些示例中,我使用的 safe navigation operator Ruby 版本比 2.3
更新。它有助于防止 NoMethodError
出现在 nil 对象上,但实际上并不是必需的。
首先让我们从一些基础知识开始。
您想更新多行并且想为每一行设置不同的值。所以它不能像你正在做的那样在单个查询中完成。因此,您需要遍历 Foo
个对象并分别设置每个对象。
所以让我们假设
str = "abc---def---ghi---jkl"
tokens = str.split('---')
foos_to_update = Foo.where(product_id: 1) #Let's assume it will return 4 or lesser records. (otherwise you need to tell what do you wanna do if it returns more then `tokens`)
foos_to_update.each_with_index {|foo,i| foo.update(bar: tokens[i])}
最后一行循环遍历返回的对象并为每个对象设置 bar
值。