Browse files

Merge pull request #111 from joaomilho/master

Add codeclimate and a common use cases section
  • Loading branch information...
2 parents 385085f + 09ce9d0 commit 5dba5d773bff9eaf77d8126ce5ce67afcad9f548 @diogob committed Aug 12, 2013
Showing with 70 additions and 23 deletions.
  1. +70 −23
@@ -1,11 +1,26 @@
-#Goodbye serialize, hello hstore. [![Build Status](](
+#Goodbye serialize, hello hstore.
+[![Build Status](](
+[![Code Climate](](
You need dynamic columns in your tables. What do you do?
* Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
* Use a noSQL database just for this issue. Good luck.
* Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
+##Common use cases
+Add settings to users, like in rails-settings or HasEasy.
+class User < ActiveRecord::Base
+ serialize :settings, ActiveRecord::Coders::Hstore
+user = User.create settings: {theme: 'navy'}
##Note about 0.7
I have decided to clean up the old code and provide only a custom serializer in this new version.
@@ -62,7 +77,7 @@ Well, not yet. Don’t forget to add indexes. Like this:
CREATE INDEX people_gist_data ON people USING GIST(data);
CREATE INDEX people_gin_data ON people USING GIN(data);
@@ -73,7 +88,7 @@ For the model Person we could create an index (defaults to type GIST) over the d
class AddIndexToPeople < ActiveRecord::Migration
def change
add_hstore_index :people, :data
- end
+ end
@@ -85,7 +100,9 @@ look at [PostgreSQL docs](
This gem only provides a custom serialization coder.
If you want to use it just put in your Gemfile:
- gem 'activerecord-postgres-hstore'
+gem 'activerecord-postgres-hstore'
Now add a line (for each hstore column) on the model you have your hstore columns.
Assuming a model called **Person**, with a **data** field on it, the
@@ -99,72 +116,100 @@ end
This way, you will automatically start with an empty hash that you can write attributes to.
- irb(main):001:0> person =
- => #<Person id: nil, name: nil, data: {}, created_at: nil, updated_at: nil>
- irb(main):002:0>['favorite_color'] = 'blue'
- => "blue"
+irb(main):001:0> person =
+=> #<Person id: nil, name: nil, data: {}, created_at: nil, updated_at: nil>
+irb(main):002:0>['favorite_color'] = 'blue'
+=> "blue"
###Querying the database
Now you just need to learn a little bit of new
sqls for selecting stuff (creating and updating is transparent).
Find records that contains a key named 'foo’:
- Person.where("data ? 'foo'")
+Person.where("data ? 'foo'")
Find records where 'foo’ is equal to 'bar’:
- Person.where("data -> 'foo' = 'bar'")
+Person.where("data -> 'foo' = 'bar'")
This same sql is at least twice as fast (using indexes) if you do it
that way:
- Person.where("data @> 'foo=>bar'")
+Person.where("data @> 'foo=>bar'")
Find records where 'foo’ is not equal to 'bar’:
- Person.where("data -> 'foo' <> 'bar'")
+Person.where("data -> 'foo' <> 'bar'")
Find records where 'foo’ is like 'bar’:
- Person.where("data -> 'foo' LIKE '%bar%'")
+Person.where("data -> 'foo' LIKE '%bar%'")
If you need to delete a key in a record, you can do it that way:
- person.destroy_key(:data, :foo)
+person.destroy_key(:data, :foo)
This way you’ll also save the record:
- person.destroy_key!(:data, :foo)
+person.destroy_key!(:data, :foo)
The destroy\_key method returns 'self’, so you can chain it:
- person.destroy_key(:data, :foo).destroy_key(:data, :bar).save
+person.destroy_key(:data, :foo).destroy_key(:data, :bar).save
But there is a shortcuts for that:
- person.destroy_keys(:data, :foo, :bar)
+person.destroy_keys(:data, :foo, :bar)
And finally, if you need to delete keys in many rows, you can:
- Person.delete_key(:data, :foo)
+Person.delete_key(:data, :foo)
and with many keys:
- Person.delete_keys(:data, :foo, :bar)
+Person.delete_keys(:data, :foo, :bar)
hstore keys and values have to be strings. This means `true` will become `"true"` and `42` will become `"42"` after you save the record. Only `nil` values are preserved.
It is also confusing when querying:
- Person.where("data -> 'foo' = :value", value: true).to_sql
- #=> SELECT "people".* FROM "people" WHERE ("data -> 'foo' = 't'") # notice 't'
+Person.where("data -> 'foo' = :value", value: true).to_sql
+#=> SELECT "people".* FROM "people" WHERE ("data -> 'foo' = 't'") # notice 't'
To avoid the above, make sure all named parameters are strings:
- Person.where("data -> 'foo' = :value", value: some_var.to_s)
+Person.where("data -> 'foo' = :value", value: some_var.to_s)
Have fun.
@@ -178,7 +223,9 @@ in database.yml to that database.
The second option is to uncomment or add the following line in config/application.rb
- config.active_record.schema_format = :sql
+config.active_record.schema_format = :sql
This will change your schema dumps from Ruby to SQL. If you're
unsure about the implications of this change, we suggest reading this

0 comments on commit 5dba5d7

Please sign in to comment.