Pretend I have a table called books
and it has a json
type column called misc
where some miscellaneous data has been saved. Using Rails/AREL I would like to extract just id
and the number of pages (num_pages
) from all the books.
In psql
I can do the following:
SELECT id, misc->'num_pages' FROM books ;
id | ?column?
-------+---------------
23562 | "220"
22188 | "355"
(Note: the above query produces the same results with -->
as with ->
).
I expected this to work:
pry> Book.select("id, misc->>'num_pages'")
Book Load(1.7ms) SELECT id, etc-->'num_pages' FROM "books"
Book Load(1.5ms) SELECT id, etc-->'num_pages' FROM "books"
=> #<Book::ActiveRecord_Relation:0x3ff7e934d8f4>
pry> Book.select("id, misc->'num_pages'")
Book Load(1.1ms) SELECT id, etc->'num_pages' FROM "books"
=> [#<Book:0x00007fefd3c11a68 id: 23562>, #<Book:0x00007fefd3c116a8 id: 22188>]
...when I remove the ->'num_pages'
part, it returns the entire misc
field (so I know it's almost working):
pry> Book.select("id, misc")
Book Load(0.9ms) SELECT id, etc FROM "books"
=> [#<Book:0x00007fefe4e99fb8
id: 23562,
etc:
{"num_pages"=>"220",
...
I can't get it done with .select
but .pluck
works in this form:
Book.pluck("id", "misc -> 'num_pages'")
=> [[23562, "220"], [22188,"355"]]
However, this will produce a deprecation warning:
DEPRECATION WARNING: Dangerous query method (method whose arguments are used
as raw SQL) called with non-attribute argument(s): "misc->'num_pages'".
Non-attribute arguments will be disallowed in Rails 6.0. This method should
not be called with user-provided values, such as request parameters or model
attributes. Known-safe values can be passed by wrapping them in Arel.sql().
So use Arel.sql()
as suggested:
Book.pluck("id", Arel.sql("misc -> 'num_pages'"))
=> [[23562, "220"], [22188,"355"]]