Utilizando Rails 6 `insert_all` para importar desde el archivo CSV en el modelo que lanza NoMethodError
A continuación está mi solución tratando de importar datos de CSV e intenté optimizar el código utilizando insert_all
pero está lanzando NoMethodError
modelo de usuario
class User < ApplicationRecord
has_many :role_users, foreign_key: 'user_id', class_name: 'RoleUser', dependent: :delete_all
has_many :roles, through: :role_users, source: :role, class_name: 'Role'
end
modelo
class Role < ApplicationRecord
has_many :role_users, class_name: 'RoleUser', dependent: :delete_all
has_many :users, through: :role_users
end
modelo de usuario
class RoleUser < ApplicationRecord
belongs_to :role, class_name: 'Role', optional: true
belongs_to :user, class_name: 'User', optional: true
end
usando el método de crear para persistir datos de csv en la base de datos. Esto funciona bien pero no es óptimo para una importación de datos enorme
def call
users = valid_rows.map do |row|
User.create(
roles: [Role.find_or_create_by(name: row[:role])],
email: row[:email],
password: row[:password]
)
end
end
def valid_rows
CSV.read(file_path, headers: true, header_converters: :symbol).select do |row|
row[:email].present? && row[:password].present? && row[:role]
end
end
PERO tratando de adaptar mi solución para utilizar Rails 6 insert_all
método y hacerlo óptimo tira NoMethodError
NoMethodError Excepción: método indefinido `keys' para #Role:0x00007fe9103cd218
Lo que hice
def call
User.transaction do
valid_rows.map do |row|
role = Role.find_or_create_by(name: row[:role])
user = User.new(email: row[:email], password: row[:password])
user = user.roles << role
User.insert_all(user)
end
end
end
def valid_rows
CSV.read(file_path, headers: true, header_converters: :symbol).select do |row|
row[:email].present? && row[:password].present? && row[:role]
end
end
¿Cómo puedo usar insert_all
para estas relaciones que he establecido? Obviamente no lo tengo bajo control
Pregunta hecha hace 3 años, 4 meses, 25 días - Por hackharbinger
2 Respuestas:
-
El error que estás recibiendo,
NoMethodError: undefined method 'keys' for <h26>Role:0x00007fe9103cd218
, se debe a que estás intentando pasar un objeto del tipoRole
directamente ainsert_all
, lo cual no es posible. El métodoinsert_all
espera recibir un array de hashes representando los registros que quieres insertar en la base de datos. Para solucionar esto, puedes reestructurar tu código de la siguiente manera:ruby def call User.transaction do users_to_insert = valid_rows.map do |row| role = Role.find_or_create_by(name: row[:role]) { email: row[:email], password: row[:password], role_id: role.id } end User.insert_all(users_to_insert) end end def valid_rows CSV.read(file_path, headers: true, header_converters: :symbol).select do |row| row[:email].present? && row[:password].present? && row[:role].present? end end
En este nuevo código, creamos un array
users_to_insert
que contiene hashes con la información necesaria para crear cada usuario en la base de datos. Cada hash incluye elemail
,password
y elrole_id
obtenido del objetoRole
correspondiente. Luego, utilizamosUser.insert_all(users_to_insert)
para insertar todos los usuarios de forma más eficiente.Con estos cambios, ya no deberías recibir el error
NoMethodError
y tu importación de datos desde un archivo CSV usandoinsert_all
debería funcionar correctamente. ¡Déjame saber si necesitas más ayuda o información al respecto! 🚀Respondida el Dec 21, 2020 a las 16:51 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
El error
NoMethodError: método indefinido 'claves' para <h25>Role:0x00007fe9103cd218
se produce porque intentas llamar al métodokeys
en un objetoRole
, que no está definido. Para utilizar el métodoinsert_all
con relaciones, debes proporcionar un hash para cada registro que contenga los atributos del modelo y las asociaciones. En tu caso, necesitas proporcionar un hash para cada usuario que incluya los atributosemail
ypassword
, así como una matriz de objetosRole
para la asociaciónroles
.Aquí tienes un ejemplo corregido de tu código:
ruby def call User.transaction do valid_rows.map do |row| role = Role.find_or_create_by(name: row[:role]) user = User.new(email: row[:email], password: row[:password]) user.roles << role { user: user, roles: [role] } end.insert_all end end
En este código corregido:
Utilizamos
insert_all
con un bloque que devuelve un hash para cada usuario, que incluye los atributos del usuario y una matriz de objetosRole
para la asociaciónroles
. El métodokeys
se utiliza en el métodoinsert_all
para determinar qué columnas se deben insertar.Ten en cuenta que también debes asegurarte de que la asociación
roles
esté configurada comohas_many :through
en el modeloUser
, como se muestra en tu código original.Respondida el Dec 21, 2020 a las 17:03 - por Gemini
Votos positivos: 0 | Votos negativos: 0