https://api.rubyonrails.org/classes/ActiveRecord/Store.html

https://gorails.com/episodes/preferences-settings-with-activerecord-store?autoplay=1

我的git:  https://github.com/chentianwei411/embeddable_comments


本次视频讲解使用ActiveRecord::Store 和增强插件 ActiveRecord-TypedStore来保存用户偏好设置,并把数据存储在一个单一的column中。

ActiveRecord::Store

Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column. It's like a simple key/value store baked into your record when you don't care about being able to query that store outside the context of a single record.

Store给你一个简单的包装把一系列相同目的的hash对象储存在一个column中。

如果你不需要对这个store的内容进行检索的话,store就像是一个简单的key/value对儿,存储在你的record中。

给这个store声明一个accessors.

⚠️注意存储类型是text。以便有足够的存储空间。

你可以设置代码来编码/解码你的属性 从/到不同的formats。JSON, YAML等。

⚠️如果使用PostgreSQL来指定columns如hstore或json,无需为这些属性提供.store,只需要使用.store_accessor来生成accessor methods。(⚠️使用的是string key,不能用symbol)

⚠️验证选项 uniqueness 默认是启用的。

视频的步骤:

不同的用户进行自定义的设置 。可以把不同功能的设置以key/value的格式放入一个hash内。这样就只需要一个column在数据库了,无需多个column(显得很乱)。

初始化一个表格:

def change
create_table :users do |t|
t.text :settings
t.json :preferences
end
end

preferences which will be a JSON column in a PostgreSQL

如果使用PostgreSQL数据库,可以使用JSON格式的列,JSON格式的列是可以被查询的。而text格式不行。

class User < ActiveRecord::Base
store :settings, accessors: [ :weekly_email, :monthly_newsletter], coder: JSON
end

解释:

  • settings将存储一个对象, :weekly_email是key,值是一个string。
  • 可以直接定义user = User.new(weekly_email: "2 weeks")
  • user.settings 会得到这个hash对象。例如 : { "weekly_email" => "xx"}
  • 可以用user.settings[:newcontent] = "xxx"的格式,增加任意的属性。
  • 使用coder: JSON 选项来编码/解码你的序列的属性。

在控制台:

u = User.last

=> #<User id: 1, settings: {"weekly_email"=>"0", preferences: nil, ...}>

但是在log上查看:是一个JSON string, 因为我们定义了code: JSON

UPDATE "users" SET "settings" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["settings", "{\"weekly_email\":\"0\"}"], ["updated_at", "xxx"], ["id", 1]]

用JSON格式编码成一个JSON string存入database中的数据格式为text的column(weekly_email),

从database取出数据后,再把JSON格式转化为Ruby hash格式。

class User < ActiveRecord::Base
store :settings, accessors: [ :weekly_email, :monthly_newsletter], coder: JSON //如果使用PostgreSQL数据库,则使用store_accessor代替store
//需要使用a string keyed hash, 不能用symbol
store_accessor :preferneces, :playback_rate //默认coder: JSON
end

⚠️: weekly_email, playback_rate需要加入params_user白名单。

<div class="field">
<%= form.label :playback_rate %>
<%= form.select :playback_rate, [0.5, 1, 1.5, 2] %>
</div>

ActiveStore的一个缺陷是不能自定义settings属性内的key的值的type类型。

因此gem 'activerecord-typedstore', 可以解决这个问题:

用法类似,也简单,和建立activerecord的migrations很像:

class Shop < ActiveRecord::Base

  typed_store :settings, coder: JSON do |s|
s.boolean :public, default: false, null: false
s.string :email
s.datetime :publish_at
s.integer :age, null: false # You can define array attributes like in rails 4 and postgres
s.string :tags, array: true, default: [], null: false # In addition to prevent null values you can prevent blank values
s.string :title, blank: false, default: 'Title' # If you don't want to enforce a datatype but still like to have default handling
s.any :source, blank: false, default: 'web'
end # You can use any ActiveModel validator
validates :age, presence: true end # 值可以像正常的model属性一样存取
shop = Shop.new(email: 'george@cyclim.se')
shop.public? # => false
shop.email # => 'george@cyclim.se'
shop.published_at # => nil # Values are type casted,用update_attributes()方法更新
shop.update_attributes(
age: '',
published_at: '1984-06-08 13:57:12'
)
shop.age # => 42
shop.published_at.class #= DateTime # 值是否变化,有对应的方法可以跟踪:
shop.age_changed? # => false
shop.age = 12
shop.age_changed? # => true
shop.age_was # => 42 # You can still use it as a regular store,可以用标准的store存取属性,但多了save
shop.settings[:unknown] = 'Hello World'
shop.save
shop.reload
shop.settings[:unknown] # => 'Hello World'

无需使用migration来增加/移除了。

默认是不能查询这些属性的,(unless you use JSON or Postgres HStore types)

使用JSON column 而不是text column的话, JSON column可以被查询:

User.where("preferences ->> 'playback_rate' = '2.0'")

另一种写法:

User.where("preferences ->> :key = :value", key: "playback_rate", value: "2.0")

->>锯齿箭头: 在preferences内 查找playback_rate的值等于2.0的记录

如果使用PostgreSQL数据库,可以使用JSON格式的列,JSON格式的列是可以被查询的。而text格式不行。

(Gorails) activeStore模块,把一堆属性放在一个hash对象内。gem 'activerecord-typedstore'增强了store模块,更好用了的更多相关文章

  1. 把模块有关联的放在一个文件夹中 在python2中调用文件夹名会直接失败 在python3中调用会成功,但是调用不能成功的解决方案

    把模块有关联的放在一个文件夹中 在python2中调用文件夹名会直接失败在python3中调用会成功,但是调用不能成功 解决办法是: 在该文件夹下加入空文件__init__.py python2会把该 ...

  2. C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西付给另一个类对象,而不是付给引用地址)

    from:https://blog.csdn.net/poxiaohai2011/article/details/27555951 //C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西 ...

  3. 返回一个集合对象,同时这个集合的对象的属性又是一个集合对象的处理方法(ViewModel)

    如果遇到需要返回一个集合对象,其中该集合中的属性又是一个集合.第一种:可在考虑用外键关联,比如在控制器中可以采用预先加载的方式加载关联的数据,比如 RoleManager.Roles.Include& ...

  4. WPF Image控件的Source属性是一个ImageSource对象

    1.固定的图片路径是可以的,如下: <Image Source="../test.png" /> 2.绑定的Path是一个String类型的图片路径,而实际情况它需要的 ...

  5. python3--__getattr__和__setattr__捕捉属性的一个引用

    __getattr__和__setattr__捕捉属性的一个引用 __getattr__方法是拦截属性点号运算.更确切地说,当通过对未定义(不存在)属性名称和实例进行点号运算时,就会用属性名称为字符串 ...

  6. js的 image 属性 和一个预加载模块

    创建一个Image对象:var a=new Image();    定义Image对象的src: a.src=”xxx.gif”;    这样做就相当于给浏览器缓存了一张图片. 图像对象: 建立图像对 ...

  7. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

  8. 为什么不能把委托(delegate)放在一个接口(interface)当中?

    stackoverflow上有人问,为什么不能把委托放在一个接口当中? 投票最多的第一个答案第一句话说,“A Delegate is just another type, so you don't g ...

  9. 一个普通的 Zepto 源码分析(三) - event 模块

    一个普通的 Zepto 源码分析(三) - event 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块, ...

随机推荐

  1. Install jdk on Ubuntu16

    wikiHow to Install Oracle Java JDK on Ubuntu Linux This tutorial will cover the installation of 32-b ...

  2. secureCRT的自动化脚本如何编写?

    以等待字符串eth0的出现,出现后或者20秒后脚本执行reboot命令的脚本为例,示例如下: #$language = "VBScript" #$interface = " ...

  3. ppoint的使用

    ppt中的所有东西都要看作是 "对象" . 对 "对象"的操作逻辑是: 单击, 右键单击,双击(右键的时候, 直接就右键, 不必先选中再右键操作) 在ppt中, ...

  4. P2120 [ZJOI2007]仓库建设(dp+斜率优化)

    思路 首先暴力DP显然,可以得20分 加上一个前缀和优化,可以得到40分 然后上斜率优化 设\(sum_i\)为\(\sum_{1}^iP_i\),\(sump_i\)为\(\sum_{1}^{i}P ...

  5. Unsupervised Image-to-Image Translation Networks --- Reading Writing

    Unsupervised Image-to-Image Translation Networks --- Reading Writing 2017.03.03 Motivations: most ex ...

  6. C++变量的默认初始化规则

    定义没有初始化式的变量时,系统有时候会帮我们初始化变量.系统如何初始化取决于变量的类型以及变量定义的位置. 内置类型变量是否自动初始化取决于变量定义的位置.函数体外定义的变量初始成0:函数体内定义的变 ...

  7. MySQL的启动和关闭

    1.Windows下 启动服务 mysqld --console 或 net start mysql 关闭服务 mysqladmin -uroot shudown 或 net stop mysql 2 ...

  8. 案例2:用一条SQL查询出数学语文成绩都大于80分的学生姓名?

    方法1: 查出科目成绩有小于80分的学生姓名,再约束并去重学生不等于查出来的姓名 select distinct A.name from t_score A where A.name not in(s ...

  9. ERR! registry error parsing json

    报错日志: ERR! registry error parsing json ERR! registry error parsing json 解决过程: 从github上克隆一个项目,在npm i的 ...

  10. C#:CsvReader读取.CSV文件(转换成DataTable)

    原文引用:https://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader using LumenWorks.Framework.IO.Csv; ...