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. linux内核中的DMI是什么?

    答: 桌面管理接口(Desktop Management Interface).是用来获取硬件信息的,在内核中有一个配置项CONFIG_DMI用来添加此功能到内核中!

  2. javascript中的高阶函数, 和 类定义Function, 和apply的使用

    参考: http://www.cnblogs.com/delin/archive/2010/06/17/1759695.html js中的类, 也是用function关键字来定义的: function ...

  3. Pollard Rho大质数分解学习笔记

    目录 问题 流程 代码 生日悖论 end 问题 给定n,要求对n质因数分解 普通的试除法已经不能应用于大整数了,我们需要更快的算法 流程 大概就是找出\(n=c*d\) 如果\(c\)是素数,结束,不 ...

  4. P4172 [WC2006]水管局长

    P4172 [WC2006]水管局长 前言 luogu数据太小 去bzoj,他的数据大一些 思路 正着删不好维护 那就倒着加,没了 LCT维护他的最小生成树MST 树上加一条边肯定会有一个环 看看环上 ...

  5. Shiro学习笔记 三(认证授权)

    第一种首先基于角色的权限控制 1.由于不断的创建SecurityFactory工程等步骤重复多次,所以应该将这些步骤封装成一个工具类 还是首先看一下目录结构 主要用到文件 首先贴一下工具类的方法 pa ...

  6. Java创建对象的几种方式。

    Java创建对象的几种方式(重要): (1) 用new语句创建对象,这是最常见的创建对象的方法. (2) 运用反射手段,调用java.lang.Class或者java.lang.reflect.Con ...

  7. Google advertiser 开发

    开发 相关知识: 单一归因与多重归因 当展示广告网络上发生一次展示时,您可按单一归因或多重归因记录对展示起到影响作用的条件. 单一归因 在使用单一归因时,系统只为指定的展示记录一个触发条件(如展示位置 ...

  8. 分布式爬虫scrapy-redis中settings.py中的配置信息

    SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 使用scrapy-redis的调度器 ITEM_PIPELINES = { 'sc ...

  9. HDU 5791 Two(LCS求公共子序列个数)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5791 题意: 给出两个序列,求这两个序列的公共子序列的总个数. 思路: 和LCS差不多,dp[i][ ...

  10. 51nod 1672 区间交(贪心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1672 题意: 思路:其实这就是一个经典的区间贪心问题,只需要按照左端点排 ...