ruby-on-rails - migraciones - migracion en rails
Rails 4-Guardar dirección como una columna en la base de datos (3)
Soy nuevo en rails y trabajo en una aplicación simple. Tengo un modelo llamado Cliente en mi ERD y me gustaría guardar la dirección para cada cliente.
Mis pensamientos iniciales sobre dónde guardar la dirección como campos separados, es decir:
rails g model Client address_first:string address_second:string city:string ...
pero esto parece muy ineficiente. Estoy seguro de que debe haber una forma de guardar la dirección sa hash, array o quizás JSON? He leído todo y la gente sigue refiriéndose al uso de "serializar", pero no estoy seguro de si implementaría esto para un campo de dirección y cómo lo implementaría.
Cualquier ayuda sería muy apreciada.
Gracias
Depende de la base de datos que esté utilizando, tanto MySQL como Postgres tienen tipos de columnas JSON. Postgres también tiene un tipo de hash llamado hstore.
También tienen diferentes opciones para consultar dentro de la columna hash / json. Si bien estos tipos de datos son excelentes para datos dinámicos, no hay una ganancia de rendimiento real (en realidad podría ser más lenta).
Y no puede usar todos los rieles de bondad del mapeo de objetos, validaciones, etc. para los atributos almacenados dentro de una columna hstore / json.
Cuando se trata de direcciones, todo el mundo lo pone ingenuamente en el modelo de Usuario (o Cliente o Cliente) solo para descubrir que en el mundo real necesita múltiples direcciones.
# == Schema Information
#
# Table name: clients
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class Client < ActiveRecord::Base
has_many :addresses
end
# == Schema Information
#
# Table name: addresses
#
# id :integer not null, primary key
# address_first :string
# address_second :string
# street :string
# city :string
# country :string
# client_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Address < ActiveRecord::Base
belongs_to :client
end
Rails está ayudando oyu
class Client
serialize :address
end
http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html
http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
Para seguir con Max''s
sugerencia Max''s
, me gustaría agregar que puede incluir información de la dirección dentro de un único modelo, si lo desea.
Tener varios modelos es genial, pero si está seguro de que solo desea ciertos atributos para su Client
, puede esforzarse por guardar un hash de opciones en una columna allí.
SQL
Para responder a su pregunta directamente y elaborar sobre la recomendación de Max, hay varios tipos de columna que puede usar, dependiendo de la variante de SQL que esté empleando.
PostgreSQL (Heroku usa esto) tiene los tipos de columna hstore
y json
.
Ambos le proporcionan una columna que le permite almacenar un solo objeto serializado, lo que le permite completar este objeto con datos serializados:
Nunca antes había usado esta funcionalidad en PGSQL
, así que será mejor que lea esta publicación de blog sobre cómo elegir entre los tipos de columna HSTORE
y JSON
.
-
MYSQL , que la mayoría de la gente usa, también tiene la capacidad de almacenar JSON :
A partir de MySQL 5.7.8, MySQL admite un tipo de datos JSON nativo que permite un acceso eficiente a los datos en documentos JSON (JavaScript Object Notation). El tipo de datos JSON proporciona estas ventajas sobre el almacenamiento de cadenas de formato JSON en una columna de cadena:
Esto parece funcionar de la misma manera que su hermano PGSQL.
Si elige uno de estos (puede usar la siguiente configuración):
#clients
#id | name | email | address (json) | created_at | updated_at
... le dará la capacidad de insertar objetos con formato JSON en la columna de address
.
Ahora, como lo señala Max
, esto evitará que ejecute validations
y otra lógica de nivel de atributo en la columna de address
. Le impedirá buscar esta columna a través de ActiveRecord y dificultará el uso de esta información en cualquier otra capacidad que no sea almacenarla.
Por lo tanto, si estaba absolutamente seguro de querer almacenarlo de esta manera, podría usar lo siguiente para hacerlo :
#app/models/client.rb
class Client < ActiveRecord::Base
serialize :address
end
#app/controllers/clients_controller.rb
class ClientsController < ApplicationController
def new
@client = Client.new
end
def create
@client = Client.new client_params
@client.save
end
private
def client_params
params.require(:client).permit(:name, :email, address:{})
end
end
#app/views/clients/new.html.erb
<%= form_for @client do |f| %>
<%= f.text_field :name %>
<%= f.email_field :email %>
<%= f.fields_for :address, OpenStruct.new(f.object.address || {}) do |address| %>
<%= address.text_field :street %>
<%= address.text_field :other_data %>
<% end %>
<%= f.submit %>
<% end %>
fields_for
available here: ¿Cómo editar un campo serializado de Rails en un formulario?
Modelos
La alternativa, como lo señala Max, es usar modelos múltiples.
Esto, aunque se ve bien, es en realidad un proceso muy delicado. Muchas personas comienzan a insertar modelos para todo, y pronto su aplicación estará llena de modelos que no hacen nada.
Si quisiera usar modelos, sería mejor que use lo siguiente:
#app/models/client.rb
class Client < ActiveRecord::Base
#columns id | name | email | etc | created_at | updated_at
has_one :address
before_create :build_address, unless: Proc.new { |client| client.address }
end
#app/models/address.rb
class Address < ActiveRecord::Base
#columns id | client_id | your | address | columns | here | created_at | updated_at
belongs_to :client
end
Solo recomendaría esto si quisieras que la dirección desempeñara un papel principal en la aplicación (por ejemplo, si se enviarán a ella, etc.).
Si está usando la dirección en cualquier otra forma no importante, la dejaría como el hash serializado.