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

时间:2015-10-14 06:45:32

标签: ruby-on-rails json ruby-on-rails-4 hash street-address

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

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

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

但这看起来非常低效。我确定必须有办法将地址保存为哈希,数组或JSON吗?我已经读完了,人们一直在指使用" serialise"但是我不确定我是否以及如何为地址字段实现这一点。

非常感谢任何帮助。

由于

3 个答案:

答案 0 :(得分:7)

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

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

并且您无法对存储在hstore / json列中的属性使用对象映射,验证等所有的优点。

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

In [42]: df = pd.DataFrame({'sku': ('SKU123', 'SKU124', 'SKU124', 'SKU125', 'SKU126', 'SKU127'), 'Cat':('CatA', 'CatB', 'CatB', 'CatA', 'CatB', 'CatC'), 'Price':(4.5, 4.7, 4.7, '', '', 4.5)})

In [43]: filtered_df = df.drop_duplicates()

In [44]: filtered_df = filtered_df[filtered_df['Price'].convert_objects(convert_numeric=True).notnull()]

In [45]: filtered_df
Out[45]:
    Cat Price     sku
0  CatA   4.5  SKU123
1  CatB   4.7  SKU124
5  CatC   4.5  SKU127

答案 1 :(得分:4)

要进一步提出Max's建议,我想添加您可以在单个模型中包含地址信息(如果需要)。

拥有多个模型很酷,但如果您确定只需要Client的某些属性,则可以尝试将选项的哈希值保存到列中。那里。

SQL

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

PostgreSQL(Heroku使用此功能)具有hstorejson列类型。

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

enter image description here

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

-

大多数人使用的

MYSQL也具有store JSON的能力:

  

从MySQL 5.7.8开始,MySQL支持启用的本机JSON数据类型   JSON中有效访问数据(JavaScript Object Notation)   文档。 JSON数据类型提供了优于存储的这些优点   字符串列中的JSON格式字符串:

这似乎与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,那么就是IE)。

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

答案 2 :(得分:0)