Rails active record query, serialized array - ruby-on-rails

Suppose I have Users data that store array of pet in String datatype
[
#<User id: 1, name: "John", pets: "---\n- cat\n- dog\n- bunny\n- ''\n">,
#<User id: 2, name: "Pete", pets: "---\n- dog\n- bunny\n- ''\n">,
#<User id: 3, name: "Jack", pets: "---\n- cat\n- ''\n">,
#<User id: 4, name: "Kurt", pets: "---\n- cat\n- bunny\n- ''\n">
]
Can i get all users that has a cat? Maybe something like User.find_all_by... or User.where(....) or anything that return as a relation? So i can order with active record query.
I know i can get all users that has a cat with
User.all.select{|s| YAML.load(s.pets).include?'cat'}
, but it convert to array that cannot be ordered with active record query.
thx for helping.

You could use simple SQL to see if 'cat' shows up in the serialized column.
User.where('pets LIKE "%cat%"').all

You need to normalize your data, add Pet model and set has_and_belongs_to_many association between theese models.

Related

How do I use an array of integers to query a jsonb column?

Ruby on Rails with postgres database.
I have an EventOccurrence model that has a jsonb column named 'details'.
I have three EventOccurrence records, like this:
EventOccurrence
id: 472,
event_type: "Event",
event_id: 19,
details:
{"text_source"=>{"id"=>215, "class_name"=>"ContentItem"}}
EventOccurrence
id: 509,
event_type: "Event",
event_id: 19,
details:
{"text_source"=>{"id"=>221, "class_name"=>"ContentItem"}}
EventOccurrence
id: 515,
event_type: "Event",
event_id: 19,
details:
{"text_source"=>{"id"=>223, "class_name"=>"ContentItem"}}
I have an array with ids, like this:
ids = [221, 223]
I'm trying to form a query that returns all EventOccurrence records where the details->text_source->id is NOT in the array. That is, I'm trying to return the EventOccurrence with id: 472.
I've tried:
EventOccurrence.where("details->'text_source' #> ?", {id: ids})
=> can't quote Array (TypeError)
EventOccurrence.where("details->'text_source'->'id' ?| array[:ids]", ids: ids)
=> (Object doesn't support #inspect)
And dozens of alternatives with no luck.
Thank you for taking a look!

Rails group_by with empty results

I have following models:
class Task
belongs_to :task_category
end
class TaskCategory
has_many :tasks
end
I want to group tasks by task category and this works for me:
Task.all.group_by(&:task_category)
# =>
{
#<TaskCategory id: 1, name: "call", ... } =>[#<Task id: 1, ...>, #<Task id: 2, ...>],
#<TaskCategory id: 2, name: "event", ... } =>[#<Task id: 3, ...>, #<Task id: 4, ...>]
}
The problem is I want all task categories returned even if the task collection is empty. Therefore, something like this would work:
#<TaskCategory id: 3, name: "todo", ... } =>[]
In this case, the task category has no tasks, so the value is an empty array. Does the group_by support an option to allow this? If not, can this be done elegantly in a one-liner?
TaskCategory.all.includes(:task) would work wouldn't it? The data you get back would be in a slightly different format, but not significantly so.
If you just do TaskCategory.all, you can get the tasks grouped by the category that you need. The format isn't exactly the same but still grouped the way you want it:
TaskCategory.all
# Assuming the first TaskCategory has no tasks
TaskCategory.all.first.tasks
=> #<ActiveRecord::Relation []>
A TaskCategory with no tasks would yield #<ActiveRecord::Relation []> which is somewhat equivalent to [].

Active Record Grouping in Ruby On Rails

record = #<ActiveRecord::AssociationRelation
[#<User id: 2, store_id: 3,location: 'xxx'>,
#<User id: 4, store_id: 3,location:'yyy'>,
#<User id: 5, store_id: 4,location:'zzz'>,
#<User id: 6, store_id: 4,location:'aaa'> ]>
How to group location in comma seperated form based on store_id in ruby to get the result as,
The location of store-id(3) should be combained with comma as (yyy,xxx),
then the location of store-id(4) should be combained with comma as (zzz,aaa)
#< store_id: 3,location:'yyy,xxx'>
#< store_id: 4,location:'zzz,aaa'>
Using Enumerable.group_by you can do it this way:
User.all.group_by(&:store_id).map{|store_id,records| {store_id: store_id, location: records.map(&:location).join(',')}}
If you want to do the grouping on database level, using the group method from ActiveRecord, it is required to have a function on the database that takes care of the concatenation, so the solution would depend on the database being used.
For example, in MySQL (see Can I concatenate multiple MySQL rows into one field?)
User.group("store_id").select("store_id, GROUP_CONCAT(location SEPARATOR ',') as location")

How would I get the names and id's out of this object?

I have an object called #groups
When I enter #groups into the console it returns this:
[#<Group id: 2, name: "another test group", creator_id: 6, updater_id: 6, created_at: "2013-11-22 17:04:14", updated_at: "2013-11-22 17:04:14">, #<Group id: 1, name: "test group", creator_id: 6, updater_id: 6, created_at: "2013-11-20 17:50:28", updated_at: "2013-11-20 17:50:28">]
I want to make an select field and populate it with each group using the options_for_select() method
So, I was going to try to get the names and id's of each group and populate it that way but I don't know how to do this.
Rather than mapping the attributes you want out of an array, you should do this the rails way by using either the options_from_collection_for_select or, even easier, you can use collection_select in your form.
You'll want to use map for this:
#groups.map {|group| [group.name, group.id]}
This will return an array of arrays, with each containing [group.name, group.id].

Query list of unique attributes

I created a Ruby array (Articles) with an attribute (category) containing repeating preset values (e.g. one of the following: "Drink", "Main", "Side").
As result I'd like to get a list of all unique values of this category attribute.
I thought about something like
Article.all.category.uniq
...but that didn't work. Here's an example array:
[#<Article id: 1, category: "Drink">, #<Article id: 2, category: "Main">, #<Article id: 3, category: "Drink">, #<Article id: 4, category: "Side">, #<Article id: 5, category: "Drink">, ]
the content of the result list I am looking for should be in this case: "Drink", "Main", "Side"
Article.all.map {|a| a.category}.uniq
should do the job.
I'd do it like this:
Article.select("distinct category").map {|a| a.category}
rather than lucapette's answer, because that kind of operations are far slower in ruby than in a database.
My code example is assuming that you're using some kind of SQL database by the way. It would look different with other kinds of databases.
In Rails 3.2
Article.uniq.pluck(:category)

Resources