我是rails的新手,也是一个简单的应用程序。我的ERD中有一个名为Client的模型,并希望保存每个客户端的地址。
我最初的想法是将地址保存为单独的字段,即:
rails g model Client address_first:string address_second:string city:string ...
但这看起来非常低效。我确定必须有办法将地址保存为哈希,数组或JSON吗?我已经读完了,人们一直在指使用" serialise"但是我不确定我是否以及如何为地址字段实现这一点。
非常感谢任何帮助。
由于
答案 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
的某些属性,则可以尝试将选项的哈希值保存到列中。那里。
要直接回答您的问题,并详细说明Max的建议, 可以使用几种列类型,具体取决于您使用的SQL的变体。< / p>
PostgreSQL(Heroku使用此功能)具有hstore
和json
列类型。
这两个提供了一个允许您存储单个序列化对象的列,允许您使用序列化数据填充此对象:
我之前从未在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)
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