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

Rails 4 - Save address as one column in database

我是 rails 的新手,正在开发一个简单的应用程序。我的 ERD 中有一个名为 Client 的模型,我想为每个客户保存地址。

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

rails g model Client address_first:string address_second:string city:string ...

但这看起来效率很低。我确定必须有一种方法可以将地址保存为散列、数组或者 JSON?我四处阅读,人们一直提到使用 "serialise",但我不确定是否以及如何为地址字段实现它。

如有任何帮助,我们将不胜感激。

谢谢

Rails 正在帮助 oyu

class Client

  serialize :address

end

http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html

http://api.rubyonrails.org/classes/ActiveModel/Serialization.html

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

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

而且您不能对存储在 hstore/json 列中的属性使用所有 rails 对象映射、验证等优点。

当谈到地址时,每个人都天真地把它放在用户(或客户或客户)模型中,结果发现在现实世界中您需要多个地址。

# == 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

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

拥有多个模型很酷,但是如果您确定您只想要 Client 的某些属性,您可以努力将选项的散列保存到那里有一个专栏。


SQL

要直接回答您的问题,并详细说明 Max 的建议, 几种您可以使用的列类型,具体取决于您 SQL 的变体雇用。

PostgreSQL (Heroku uses this) has the hstorejson 列类型。

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

我以前从未在 PGSQL 上使用过此功能,所以你最好 reading this blog post on how to choose between HSTORE and JSON column types

--

MYSQL, which most people use, also has the capacity to store JSON:

As of MySQL 5.7.8, MySQL supports a native JSON data type that enables efficient access to data in JSON (JavaScript Object Notation) documents. The JSON data type provides these advantages over storing JSON-format strings in a string column:

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


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

#clients
#id | name | email | address (json) | created_at | updated_at

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

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

因此,如果您完全确定要以这种方式存储它,则可以 use the following to do it:

#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 可在此处获取:How to edit a Rails serialized field in a form?


型号

正如 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

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

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