I would like to sort data of my model base on a specific order.
Model: Grade
Table Column: category, value
values of category: Prelim, Midterm, Semi-finals, Finals
How do I sort the table Grade base on it's category with value of "Prelim, Midterm, Semi-Finals, Finals"?
If you dont want to replace them by numbers in the table as suggested by #titibouboul . You can just do.
class Grade
CATEGORY_IN_ORDER = ["Prelim", "Midterm", "Semi-Finals", "Finals"]
scope :ordered_by_category, lambda {"order(FIELD(category,#{CATEGORY_IN_ORDER.join(',')}))"}
end
then anywhere you can use this scope as:
Grade.ordered_by_category.where(YOUR_CRITERIA)
if you dont want to define scopes:
Grade.where(YOUR_CRITERIA).order("FIELD(category,#{CATEGORY_IN_ORDER.join(',')})")
More about order by FIELD syntax here:
http://www.electrictoolbox.com/mysql-order-specific-field-values/
You should replace them by a number :
1 = Prelim
2 = Midterm
3 = Semi-finals
4 = Finals
and then sort them in the model like this :
class Grade
...
default_scope -> { order('category ASC') }
...
end
Related
The following code gives an empty scope. Category_ids is an array of categories.
scope :art, ->{ where(:category_ids => '1') }
How do I check to see if one of the categories exist in the array?
If you use Postgres you can use this approach: https://www.viget.com/articles/searching-serialized-fields-in-rails-using-postgres-arrays
get the categories
correct your where query
Example:
has_many :categories
scope :art, -> { required = [Category.first]; where(categories: required) }
I assume that in your model, you have categories association. In this case, you can just use categories: required in your where query. required should be set to an array of categories which you wanted
You say that category_ids is an array of categories(I'm assuming category id's). Are you trying to return all records with a category ID that is in that array? If so you're looking for:
scope :art, -> { where (:category_id => category_ids) }
Or with the new ruby syntax:
scope :art, -> { where(category_id: category_ids) }
If I've misunderstood and you're looking for any record with a category ID of 1, then you're looking for:
scope :art, -> { where(category_id: '1') }
I have two tables that are something like:
users
id
name
active
items
id
user_id
color
Using Rails, I want to select the active users along with the number of items that are red or blue.
Something like:
User.where(active: true).joins(:items).where(items: {color: ['red', 'blue']}).count(:items)
I want the result to be an array of Users where the Users have an annotated number of items.
So it could end up like users = activerecord query, users.first.name == 'John', users.first.items_count == 3
What would you do?
Considering the color filter, I'd just do the count in ruby.
class User
scope :active, -> { where(active: true) }
def items_of_color(colors)
items.select{ |i| i.color.in?(colors) }
end
end
in the controller
#users = User.active.preload(items)
and then in the view, count the red and blue
user.items_of_color(['red', 'blue']).size
But, if RED and BLUE are special and commonly referenced, you can do this...
class User
...
has_many :red_and_blue_items, where -> ({color: ["red", "blue"]}), class_name: "Item"
end
And then, preload like so
#users = User.active.preload(:red_and_blue_items)
In the view
#users.first.red_and_blue_items.size
I don't say it is the solution, but this following statement
Item
.joins(:user)
.group(:user_id)
.where(users: { active: true }, color: ['red', 'blue'])
.count
return a list of user_id with its associated item count:
{
user_id_1 => count_1,
user_id_2 => count_2,
user_id_3 => count_3,
...
}
I have a Properties model which is using a field to sort by property type(properties.kind).
class Property < ActiveRecord::Base
scope :house, -> { where(kind: "House") }
scope :apartment, -> { where(kind: "Apartment") }
scope :commercial, -> { where(kind: "Commercial") }
end
Then in my Properties controller I'm combining them into an array so that I can group them by type in the view.
class PropertiesController < ApplicationController
def index
#house = Property.house.all
#apartment = Property.apartment.all
#commercial = Property.commercial.all
#listing = [#house, #apartment, #commercial]
end
The problem that stands out to me is that the model must perform at least 3 SQL queries on the same table for every index action. Obviously this is super inefficient, and ill be lucky if I can serve more than one user at a time.
My question is this: is there a better way to group an array's contents by a string value?
You can combine these into a single query and keep them scoped as follows:
scope :listing, -> { where(kind: ["House","Apartment","Commercial"]) }
Passing an array to Where is an alias in SQL for IN, which will cover all 3 options in one query. You could then split them out with a group_by for assigning them to instance variables.
I have a huge complex query like this:
#objects = Object.joins({ x: :y }).includes(
[:s, { x: { y: :z } }, { l: :m },:q, :w,
{ important_thing:
[:h, :v, :c,:l, :b, { :k [:u, :a] }]
}
]).where(conditions).order("x.foo, x.bar")
Then i want to show all Objects and only Important_things that were created at between two dates.
If i put this on there where clause i dont get all Objects, only Objects that has Important_things between informed dates.
A solution using raw sql was this:
select * from objects left join important_things on important_things.object_id = objets.id and important_things.created_at between 'x' and 'y'
Instead of:
select * from objects left join important_things on important_things.object_id = objets.id where important_things.created_at between 'x' and 'y'
I really need all those objects and i don't want to use a raw SQL, any workaround or a possibility to pass parameters to the ON clause on an association?
I do this,
class VendorsRatings < ActiveRecord::Base
def self.ratings(v_ids,sort = "DESC")
joins("RIGHT OUTER JOIN vendors_lists v
ON v.vendor_id = vendors_ratings.vendor_id").where(conditions)
end
end
I did a ugly workaround:
class Parent < ActiveRecord::Base
cattr_accessor :dt_begin, dt_end
has_many :children, conditions: Proc.new { { created_at: (##dt_begin..##dt_end) } }
end
class MetasController < ApplicationController
def index
Parent.dt_begin = Date.parse(param[:dt_begin])
Parent.dt_end = Date.parse(param[:dt_end])
#parents = Parent.includes(:children).where("children.age = ?", params[:age])
end
end
So this way i get all Parents even if i dont have Children created_at between those specified dates.
And the most important part of it i have all objects inside the ActiveRecord.
But be careful because i did messed with cattr_accessor so i have to set everytime before i search for Parents.
I have an array of instances of model Foo. Foo is an Ohm based data store. Each instance of Foo has an_id and integer attributes such as follows, likes. If there are two instances of Foo with the same an_id, I'd love to add the follows and likes attributes together. The solution I had was to create a hash where each key is an an_id of the array, and keep the state there. If the array is large enough, this is not efficient as I need each object back into an array. I'd love to group the array by Foo#an_id and merge/add the counter attributes together and pop that back into the array. Is something like this currently supported?
group_by, sum
As a start, something like this:
grouped_hash = your_array.group_by(&:an_id)
sums_by_id = {}
grouped_hash.each do |id,values|
sums_by_id[id] = {}
# you could also just iterate over values once and += :follows and :likes
sums_by_id[id][:follows] = values.sum(&:follows)
sums_by_id[id][:likes] = values.sum(&:likes)
end
Example output:
sums_by_id => {1 => {:follows => 2, :likes => 4}, 2 => ...
Additionally, take a look at:
inject
(5..10).inject {|sum, n| sum + n } # 45
You can use inject to get a sum of values:
array = *array of Foo*
total = array.inject { |sum, x| sum + x.likes }