我有一个 Rails 用户表,其中包含 first_name 和 last_name 列等。我如何将这两者合并在一起?或者我如何创建一个名为 name 的新列并从这两列添加数据?基本上我需要一个名为 name 的列,它是 first_name 和 last_name 的串联。
5 回答
正如 Richard Brown 所回答的那样,如果要将连接的字符串保存到数据库中,则应该创建一个迁移。
rails g migration add_fullname_to_users fullname
然后在生成的迁移中运行 sql 以更新所有记录
# mysql
User.update_all('fullname = CONCAT(first_name, " ", last_name)')
# postgre
User.update_all("fullname = (first_name || ' ' || last_name)")
但我建议您保留当前设置并在模型中创建一个名为 fullname 的方法
# user.rb
def fullname
"{first_name} #{last_name}"
end
哪个更好,因为您可以访问first_name
和last_name
如果要确保可以回滚,可以在迁移文件中执行类似的操作。
def up
add_column :your_table, :name, :string
YourClass.all.each do |person|
person.update_attributes! :name => person.first_name + " " + person.last_name
end
remove_column :your_table, :first_name
remove_column :your_table, :last_name
end
以及您的回滚方法:
def down
add_column :your_table, :first_name, :string
add_column :your_table, :last_name, :string
YourClass.all.each do |person|
person.update_attributes! :first_name => person.name.match(/\w+/)[0]
person.update_attributes! :last_name => person.name.match(/\w+/)[1]
end
remove_column :your_table, :name
end
创建迁移以添加新字段:
rails g migration AddNameToTableName name
您可以编写一个 rake 任务来执行连接。
TableName.all.each do { |row| row.update_attributes(name: "#{row.first_name} #{row.last_name}") }
您可以从 rails 控制台执行该操作,但我喜欢可重复的数据库更新,因此我更喜欢 rake 任务。
上面示例中的 \w 正则表达式匹配器和与空格连接对我来说是有问题的,尽管我遇到了相反的问题,将名字分成名字和姓氏。相反,考虑使用我最终得到的东西。首先备份您的数据库,并在开发中进行测试!
def up # Split name into first and last
add_column :people, :first_name, :string
add_column :people, :last_name, :string
Person.all.each do |person|
person.update_column(:first_name, person.attributes["name"].rpartition(" ").first)
person.update_column(:last_name, person.attributes["name"].rpartition(" ").last)
person.save(:validate => false)
end
remove_column :people, :name
end
def down # Merge first and last into name
add_column :people, :name, :string
Person.all.each do |person|
person.update_column(:name, [person.attributes["first_name"].to_s, person.attributes["last_name"].to_s].reject(&:blank?).join(" "))
person.save(:validate => false)
end
remove_column :people, :first_name
remove_column :people, :last_name
end
这样可以避免在其中一个名称为 nil 的情况下插入杂散空格,并且还可以更有效地将全名拆分为名字和姓氏;具体来说,通过拆分名称中的最后一个空格,因为“First Middle”“Last”比“First”“Middle Last”更像是人类兼容的拆分。查看示例:
# Before split
> puts p.name.inspect
"Prince"
"Test User"
"Jean Luc Picard"
# After split
> puts p.first_name.inspect + " " + p.last_name.inspect
"" "Prince"
"Test" "User"
"Jean Luc" "Picard"
我的主要抱怨是“Prince”可能应该是名字而不是姓氏,但是根据您的数据库限制,它可能仍然需要进入 last_name 字段。
在我的带有用户模型的 rails 4 应用程序中,我生成了我的迁移文件
rails g migration RemoveFirstLastNameColumnsFromUser
然后我放入
class RemoveFirstLastNameColumnsFromUser < ActiveRecord::Migration
def up
add_column :users, :name, :string
User.all.each do |u|
u.update! name: "#{u.first_name} #{u.last_name}"
end
remove_column :users, :first_name
remove_column :users, :last_name
end
def down
add_column :users, :first_name, :string
add_column :users, :last_name, :string
User.all.each do |u|
n = u.name
u.update! last_name: n.slice!(/\w+\z/)
u.update! first_name: n.strip
end
remove_column :users, :name, :string
end
end
此#down
方法将解释具有多个空格的名称。