Query list of unique attributes - ruby-on-rails

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)

Related

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 [].

allow duplicate taggings using acts-as-taggable-on

Rails newbie here!
I am using acts-as-taggable-on to implement basic tagging, but I want to modify the default behaviour so that each instance of a model (say a post) can be tagged multiple times using the same tag.
#post.tag_list.add("awesome, awesome", parse: true)
would only create one tag and one tagging in the default behavior. I would like it to use the same tag in the database but to create two unique taggings for that post.
Ultimately I would like to be able to count the number of times #post was tagged with "awesome" so I can make a tag frequency count for each post. What would be the best way to do this that wouldn't require rolling my own tag implementation?
I'm trying to add duplicate tags to a user. I want some user x to have multiple "awesome" tags. The default implementation wont let me.
Default implementation:
#instance.tag_list = "awesome, awesome, awesome"
#instance.save
#instance.reload
#instance.tags =>
[#<ActsAsTaggableOn::Tag id: 1, name: "awesome", taggings_count: 1>]
I want taggings_count to return 3 instead, because I want to make 3 separate taggings to "awesome" even though they all refer to the same tag.
This library already counts the tags. just look at attribute taggings_count of tag record.
As from docs:
#user.tag_list = "awesome, slick, hefty"
#user.save
#user.reload
#user.tags
=> [#<ActsAsTaggableOn::Tag id: 1, name: "awesome", taggings_count: 1>,
#<ActsAsTaggableOn::Tag id: 2, name: "slick", taggings_count: 1>,
#<ActsAsTaggableOn::Tag id: 3, name: "hefty", taggings_count: 1>]
Taggings_coungs is the number of taggings applied.

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].

Rails active record query, serialized array

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.

Manipulating ActiveRecords using only a few attributes with Ruby on Rails

For caching matters, I'm caching an array of the attributes of the objects I need:
friends = [{:id => 4, :name => "Kevin"}, {:id => 12, :name => "Martin"}, …]
Is it possible to have a list of Users using this array, so that I can use Ruby methods? For instance, I usually get a list of non-friends with this:
non_friends = User.all - current_user.friends
Here, current_user.friends would be replaced by the cached array, only with the cached attributes:
friends = [
#<User id: 4, name: "Kevin", created_at: nil, updated_at: nil, email: nil>,
#<User id: 12, name: "Martin", created_at: nil, updated_at: nil, email: nil>,
…
]
Is it possible? Is it a good approach to caching? (a big list of ActiveRecords doesn't fit into a 1MB Memcache chunk.)
Thank you,
Kevin
edit: The idea behind this is to use a sorted/processed list of 2000 ActiveRecords around which my app heavily uses, but since it doesn't fit into a Memcache chunk, I'm trying to cache the interesting attributes only as an array. Now, how can I use this array like it was an ActiveRecord array?
Well, you can just cache the User IDs and then exclude these IDs in your finder conditions. In your example, assuming you have a friends array of hashes containing ids and names:
friend_ids = friends.map{ |f| f[:id] }
if friend_ids.empty?
non_friends = User.all
else
non_friends = User.all(:conditions => ['id NOT IN (?)', current_user.friend_ids])
end

Resources