ActiveRecord next item - ruby-on-rails

I am currently getting back a list of items in a prioritized order:
#priotizedorder = #categories.order(:priority)
What I want to create is a button that allows a user to get to the next category from an item. I'm trying to do that by saying:
#activecategory = #categories.where(:name => params[:cat]).first
#nextcategory = #priotizedorder.select {|item|'name' == #activecategory}
But that's returning an empty array:
[]
How do I select the next category in an active record?

Firstly, your question is not clear to me, you are asking for next category but you are searching the given category in the order, according to my knowledge I am providing the solution
Your statement must be
#nextcategory = #priotizedorder.select {|item| item == #activecategory}
When you are using 'select', above statement returns an array of results matching with the value, you should take the first value from the array.
i.e., #nextcategory = #priotizedorder.select {|item| item == #activecategory}.first
(OR) You can use find method
#nextcategory = #priotizedorder.find {|item| item == #activecategory}
If you want to select the next prioritised category of given item, then use the below code
#currentcategory = #priotizedorder.find {|item| item == #activecategory}
#currentcategory_index = #priotizedorder.index(#currentcategory)
#nextcategory = #priotizedorder[#currentcategory_index+1]

Related

Select certain record within response from ActiveRecord

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 }

Searching array of objects for item in Ruby

I am trying to search through an array of objects for a value, but am having trouble getting the find_index to work. In my code below, I am trying to search for the name (joseph) in the array. Is this the best way? I want to return that object after I search and find it.
name = "joseph"
array = [{"login":"joseph","id":4,"url":"localhost/joe","description":null},
{"login":"billy","id":10,"url":"localhost/billy","description":null}]
arrayItem = array.find_index {|item| item.login == name}
puts arrayItem
Your array contains a Hash, with keys that are symbols (in hashes, key: value is a shorthand for :key => value). Therefore, you need to replace item.login with item[:login]:
name = "joseph"
array = [{"login":"joseph","id":4,"url":"localhost/joe","description":nil},
{"login":"billy","id":10,"url":"localhost/billy","description":nil}]
arrayIndex = array.find_index{ |item| item[:login] == name }
puts arrayIndex
The code above retrieves the index at which the sought object is in the array. If you want the object and not the index, use find instead of find_index:
arrayItem = array.find{ |item| item[:login] == name }
Also, note that in Ruby, null is actually called nil.

How to modify an attribute of a certain item in a model

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 *")

Check if string contains element in Array

I'm using Rails and learning ActiveRecord and I came across a vexing problem. Here's an array in my model:
#sea_countries = ['Singapore','Malaysia','Indonesia', 'Vietnam', 'Philippines', 'Thailand']
And here's my ActiveRecord object:
#sea_funding = StartupFunding.joins(:startup)
.where('startups.locations LIKE ?', '%Singapore%')
What I'm trying to do is to return a result where a string in the 'locations' column matches any element in the Array. I'm able to match the strings to each element of an Array (as above), but I'm not sure how to iterate over the whole Array such that the element is included as long as there's one match.
The intent is that an element with multiple locations 'Singapore,Malaysia' would be included within #sea_funding as well.
Well, don't ask me why 'locations' is set as a string. It's just the way the previous developer did it.
You use an IN clause in your .where filter:
#sea_funding = StartupFunding.joins(:startup)
.where(["startups.locations IN (?)", #sea_countries])
#sea_countries.include?(startups.locations)
This will return a boolean TRUE if the value of the locations column in startups can be found in the sea_countries array, false if it is absent.
Could this work for you?
first = true
where_clause = nil
sea_countries.each do |country|
quoted_country = ActiveRecord::Base.connection.quote_string(country)
if first
where_clause = "startups.locations LIKE '%#{quoted_country}%' "
first = false
else
where_clause += "OR startups.locations LIKE '%#{quoted_country}%' "
end
end
#sea_funding = StartupFunding.joins(:startup)
.where(where_clause)

find_by_sql or array issue

I'm having issues and I can't tell if it's with find_by_sql, something with the array object, or my logic. The following code is in a helper. This app has a coordinate grid with 4 quadrants. I replaced the app name with Something, so any references with that are to protect the app at the moment. I know this code may be convoluted, but I wanted to get it working first before anything else. Basically, the problem is this: When I run the SQL query, I get the results I expect back. When it hits coordinates that are children of the same parent, it'll draw one of them correctly, but when it gets to the delete, it will delete both coordinates from the array. If it makes a difference, the join table ids are getting returned as the parent coordinate's id. I tried selecting only what I needed, and that didn't help (as per the solution from this thread: http://www.sitepoint.com/forums/showthread.php?415007-rails-join-creates-wrong-id). Any help would be greatly appreciated.
To further elaborate, there are 16 parent coordinates in a quadrant. If it's blank, we draw a blank one (as per the first if), if it is not blank, we have to draw a div to collect all the children (first if of the else), then, we are supposed to be drawing all the children in there, and closing off the div and moving on. Hope this helps.
def buildQuadrantForUser(options={})
buffer=""
user_coordinates = SomethingUser.find_by_sql('
Select * from something_users
inner join coordinates as a on
`something_users`.coordinate_id = `a`.id
inner join coordinates as b on
b.id = a.ancestry
Where ((user_id = '+options[:user].id.to_s+') AND (visibility = 2) AND (a.quadrant = '+options[:quadrant].to_s+'))
Order By b.number ASC
')
i=0
while i<16 do
i+=1
first = true
drawn = false
l3num = 0
user_coordinates.collect{|coor|
puts "quadrant #{options[:quadrant].to_s}"
if !coor.number.to_i.eql?(i)
puts "quadrant: #{options[:quadrant].to_s}, number: #{i.to_s}, coordinate #{coor.id}"
if drawn == false
buffer<<"<div id=q"+options[:quadrant].to_s+"_"+i.to_s+" class='l2_div sc0'>"
buffer<<"</div>"
drawn = true
end
else
puts "quadrant: #{options[:quadrant].to_s}, number: #{i.to_s}, coordinate #{coor.inspect}"
drawn = true
if first == true
buffer<<"<div id=q"+options[:quadrant].to_s+"_"+coor.number.to_s+" class='l2_div sc#{coor.coordinate.parent.percent_clicks_user_children(:user=>options[:user])}' data-value=#{coor.coordinate.parent.name} something-rating=#{coor.coordinate.parent.id.to_s}>"
first = false
end#end first
l3num = l3num + 1
if coor.coordinate.static?
if !current_user.blank? && coor.user_id == current_user.id
buffer<<content_tag(:div, content_tag(:span, "", :id=>'You'),:class=>"l3_#{l3num.to_s} cic#{coor.coordinate.percent_clicks_user(:user=>options[:user])}", :user=>'You', :somethingsomething=>coor.something_id.to_s,:something=>coor.something_id.to_s,:id=> "e" + coor.something_id.to_s, :rating=>coor.coordinate.name.to_s, :tag=>coor.something.tags.collect{|tag| tag.name+","}, :date=>time_ago_in_words(coor.updated_at), :source=>coor.something.url.split('/')[2], :link=>coor.something.url)
else
buffer<<content_tag(:div, content_tag(:span, "", :id=>coor.user.name),:class=>"l3_#{l3num.to_s} cic#{coor.coordinate.percent_clicks_user(:user=>options[:user])}", :user=>coor.user.name, :something=>coor.something_id.to_s,:id=> "e" + coor.something_id.to_s, :rating=>coor.coordinate.name.to_s, :tag=>coor.something.tags.collect{|tag| tag.name+","}, :date=>time_ago_in_words(coor.updated_at), :source=>coor.something.url.split('/')[2], :link=>coor.something.url)
end
else
l3num = l3num-1 if l3num !=0
if !current_user.blank? && coor.user_id == current_user.id
buffer<<content_tag(:div, content_tag(:span, "", :id=>'You'),:class=>"l3_5 cic#{coor.coordinate.percent_clicks_user(:user=>options[:user])}", :user=>'You', :user=>coor.something.title,:something=>coor.something_id.to_s,:id=> "e" + coor.something_id.to_s, :rating=>coor.coordinate.name.to_s, :tag=>coor.something.tags.collect{|tag| tag.name+","}, :date=>time_ago_in_words(coor.updated_at), :source=>coor.something.url.split('/')[2], :link=>coor.something.url)
else
buffer<<content_tag(:div, content_tag(:span, "", :id=>coor.user.name),:class=>"l3_5 cic#{coor.coordinate.percent_clicks_user(:user=>options[:user])}", :user=>coor.something.title, :something=>coor.something_id.to_s,:id=> "e" + coor.something_id.to_s, :rating=>coor.coordinate.name.to_s, :tag=>coor.something.tags.collect{|tag| tag.name+","}, :date=>time_ago_in_words(coor.updated_at), :source=>coor.something.url.split('/')[2], :link=>coor.something.url)
end
end#end static
buffer<<"</div>"
puts "deleting #{coor.inspect}"
user_coordinates.delete(coor)
end#end coordinate.number = i.to_s
}
end#end while
return buffer
end
Array#delete removes any objects that are equal to the argument you give it.
For Active Record objects, equality is defined as having the same id.
You are doing select * but active record doesn't see table1.id, table2.id etc. - the columns shadow each other so when you too coor.id you'll get one of the id columns from the result set.
Given that this is what defines equality, that's obviously a bad thing - say for example that active record arbitrarily picked b.id to be its id, then when you remove that row from the array you'll remove every row where b.id had that value. I'm guessing you've been playing around with what you select, unless you select something such that each object has a different id Array#delete won't play ball
Also, you really shouldn't modify a collection while you are iterating over it.
Managed to get this fixed after a few more hours of work by restricting all ids from being selected. I ended up not deleting anything and had to restructure a lot of that code. For those trying to figure out the weird IDs in their join, definitely restrict what you're selecting.

Resources