Rails 4 - 将地址保存为数据库中的一列

Cra*_*aig 4 hash json ruby-on-rails street-address ruby-on-rails-4

我是rails的新手,也是一个简单的应用程序.我的ERD中有一个名为Client的模型,并希望保存每个客户端的地址.

我最初的想法是将地址保存为单独的字段,即:

rails g model Client address_first:string address_second:string city:string ...
Run Code Online (Sandbox Code Playgroud)

但这似乎效率很低.我确定必须有一种方法来保存地址哈希,数组或者JSON?我已经阅读过并且人们一直在指使用"序列化",但我不确定是否以及如何为地址字段实现此功能.

非常感激任何的帮助.

谢谢

max*_*max 7

这取决于您使用的数据库--MySQL和Postgres都有JSON列类型 - Postgres也有一个名为hstore的哈希类型.

它们在hash/json列中也有不同的查询选项.虽然这些数据类型非常适合动态数据 - 但没有真正的性能提升(实际上可能更慢).

而且你不能对存储在hstore/json列中的属性使用对象映射,验证等所有的轨道优点.

当涉及到地址时,每个人都天真地将其置于用户(或客户端或客户)模型中,仅发现在现实世界中您需要多个地址.

# == 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
Run Code Online (Sandbox Code Playgroud)


Ric*_*eck 5

为了进一步Max's提出建议,我想补充一点,如果需要,您可以在单个模型中包含地址信息。

拥有多个模型很酷,但如果您确定您只需要某些属性Client,您可以努力将选项散列保存到其中的列中。


SQL

要直接回答你的问题,并就最大的建议阐述,也可以使用几种列类型,取决于你使用的SQL的变种。

PostgreSQL(Heroku 使用它)具有hstorejson列类型。

这两个都为您提供了一个列,允许您存储单个序列化对象,允许您使用序列化数据填充此对象:

在此处输入图片说明

我以前从未使用过此功能PGSQL,因此您最好阅读这篇关于如何在HSTOREJSON列类型之间进行选择的博文

——

大多数人使用的MYSQL也具有存储 JSON的能力:

从 MySQL 5.7.8 开始,MySQL 支持原生 JSON 数据类型,可以有效访问 JSON(JavaScript Object Notation)文档中的数据。与将 JSON 格式的字符串存储在字符串列中相比,JSON 数据类型具有以下优势:

这似乎与其 PGSQL 兄弟的工作方式相同。


如果您确实选择其中之一(您可以使用以下设置):

#clients
#id | name | email | address (json) | created_at | updated_at
Run Code Online (Sandbox Code Playgroud)

...它将使您能够将 JSON 格式的对象插入到address列中。

现在,正如 所指出的Max,这将阻止您validationsaddress列上运行和其他属性级逻辑。它会阻止您通过 ActiveRecord 查找此列,并且将很难以任何其他方式使用此数据,而不仅仅是存储它。

因此,如果您绝对确定要以这种方式存储它,则可以使用以下方法来做到这一点

#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 %>
Run Code Online (Sandbox Code Playgroud)

fields_for此处可用:如何编辑表单中的 Rails 序列化字段?


楷模

正如 Max 所指出的,另一种方法是使用多个模型。

这虽然看起来不错,但实际上是一个非常微妙的过程。许多人开始为所有内容插入模型,很快您的应用程序就充满了不做任何事情的模型。

如果您想使用模型,最好使用以下方法:

#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
Run Code Online (Sandbox Code Playgroud)

如果您希望地址在应用程序中发挥重要作用,我只会推荐这个(IE,如果他们要运送到它等)。

如果您以任何其他不重要的形式使用该地址,我会将其保留为序列化哈希。