I have a model called Category which contains categories that are used to categorise products. One of the categories is called Experiences. On a specific query, I'd like to modify it from Experiences to Experiences * for display purposes.
I have tried to do this via a map, but am getting a blank value for Experiences.
This is my code:
def self.with_exp_star
Category.all.map { |element|
if element.name == "Experiences"
element.name = "Experiences *"
else
element
end
}
end
Any ideas?
Well, when element.name == "Experiences" you are pushing element.name to the result array, but element object otherwise, while you should return element in both ways:
Category.all.map { |element|
element.name += ' *' if element.name == 'Experiences'
element
}
If you're using rails 3 upwards you can chain a query with update_all, like so:
Categories.where(:name => "Experiences).update_all(:name => "Experiences *")
Related
I have a hash with products.
products = Product.all
I want to map through the hash and remove an object from the hash if a certain conditions is met.
products.map do |product|
product.delete if product.color == red
end
But this removes the object from the database. I only want to remove it from the products hash.
This is a simplified example where I could use SQL where statements. But in my real example this is more complex.
You can use Array#reject:
products.reject { |product| product.color == 'red' }
Or it's opposite Array#select:
products.select { |product| product.color != 'red' }
I have a call to ActiveRecord in my controller as so:
#configurations = EmailConfiguration.where(customer_id: '1', email_template: '1')
This will return all EmailConfigurations that have the correct parameters. Each record has a field_id and a the_value. I want to display the value in the view:
#configurations.where(field_id: 1).the_value
What do I need to add to the view to select a certain record within the collection that is returned by the database?
You can use select for a quick filter on arrays
#configurations.select {|c| c.field_id == 1}
that will return all collections with field_id = 1. If you know there is only one, you could chain it for a direct output:
#configurations.select {|c| c.field_id == 1}.first.the_value
#configurations.where(field_id: 1)
returns a collection of objects(array) even if there is only one result. If you would like to show only one you can do as suggested above:
#configurations.select {|c| c.field_id == 1}.first.the_value
If you want to show all of the "the_values" you can do
field_1_configs = #configurations.select do |c| c.field_id == 1
end
field_1_configs.map{|config| config.the_value }
I have a collection/array in rails, transformed to json it looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"342","item":"Pencil"},{"order_number":"877","item":"Keyboard"}]
I would like to pick the item with the order_number "342" and put it at the last position of the collection, so the new collection looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"877","item":"Keyboard"},{"order_number":"342","item":"Pencil"}]
In theory, it would look like this:
#collection.last = #collection[3]
but that is obviously not fancy ruby style nor would it re-sort the array as in my example.
Also I don't know the index of the item as it can change depending on what the user shops.
how about:
#collection << #collection.delete_at[#collection.index{|x| x[:order_number] == "342"}]
This basically searches the index of element with :order_number 342 first, uses that index to delete it, and then store the deleted element at the end again.
You can also use the partition method:
#collection = #collection.partition { |h| h['order_number'] != '342' }.flatten
Just split your collection on two (without 342 order and with 342 order), then just join them. It should looks like:
#collection = #collection.select {|e| e[:order_number] != '342' } + #collection.select {|e| e[:order_number] == '342' }
If you have an index of an item it boils down to
#collection << #collection.delete_at(3)
If you don't, you could try finding it using
#collection.find_index{ |el| el["order_number"] == "123" }
Alternative you can try this too:
> #collection.each_with_index{ |key,value| #collection.push(#collection.delete_at(value)) if key[:order_number] == "344" }
#=>[{:order_number=>"123", :item=>"Paper"}, {:order_number=>"567", :item=>"Ruler"}, {:order_number=>"342", :item=>"Pencil"}, {:order_number=>"877", :item=>"Keyboard"}, {:order_number=>"344", :item=>"Pen"}]
I have a Product model which has many Items. The application lists unique items which belong to a product. So think of items as inventory. The following query grabs featured items for a product and removes the first item (irrelevant, but it becomes a featured item, displayed separately, if you're curious).
# product.rb
has_many :items_in_stock, -> { Item.in_stock }, class_name: 'Item'
def featured_items
items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }[1..-1]
end
# item.rb
scope :in_stock, -> { where(status: 'in_stock') }
The trouble is when the feaured_items are empty, the method returns nil, and not a relation object. This means I get an error if I call #product.featured_items.any? on a product that has no items. If I remove the sort_by block, I get an empty relation object.
Is there a good way to handle this other than:
items = items_in_stock.select("DISTINCT ON (condition) id, items.*").order(:condition, :price)
if items.any?
items.sort_by { |item| item[:price] }[1..-1]
end
I can't reverse the ordering of the query because I get an error saying the order of the conditions in the order by statement must match the group conditions.
I'm confused...why call .any? on it then since nil is treated as false in ruby. If what you get back is nil then you know that you don't have any featured_items.
I ran this in irb and I think your issue is the [1..-1].
a = []
# => []
a.sort_by { |w| w.length }
# => []
a.sort_by { |w| w.length }[1..-1]
# => nil
The easiest way is to just do
items = items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }
items.any? ? items[1..-1] : items
Then you don't actually have to do a check in other parts of your code unless it's necessary.
instead of if items.any? you can use unless items.blank? if it's nil or empty, it won't run the condition
items.blank? checks both items.empty? and items.nil?
And of course you can use it in your featured_items
items = items_in_stock.select("DISTINCT ON (condition) id, items.*")
.order(:condition, :price)
.sort_by { |item| item[:price] }[1..-1]
return Array.new if items.blank?
That way you know that result will be an array, no matter what
And for the proof, you can use .blank? on a nil object, and it works on nil itself, nil.blank? returns true
I implemented a function to group anagrams.
In a nutshell:
input: ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', scream']
output: [["cars", "racs", "scar"], ["four"], ["for"], ["potatoes"],["creams", "scream"]]
I would like to know if there is a better way to do this.
I really think I used too much repetition statements: until, select,
delete_if.
Is there any way to combine the select and delete_if statement? That
means, can selected items be automatically deleted?
Code:
def group_anagrams(words)
array = []
until words.empty?
word = words.first
array.push( words.select { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) } )
words.delete_if { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) }
end
array
end
Thanks in advance,
Like that:
a = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream']
a.group_by { |element| element.downcase.chars.sort }.values
Output is:
[["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]
If you want to you can turn this one-liner to a method of course.
You could use the partition function instead of select, implemented in Enumerable. It splits the entries within the array according to the decision-function into two arrays.
def group_anagrams(words)
array = []
until words.empty?
word = words.first
delta, words = words.partition { |match| word.downcase.chars.sort.join.eql?(match.downcase.chars.sort.join ) } )
array += delta
end
array
end
(untested)