Ruby on Rails: remove element from array by id - ruby-on-rails

Is there some sort of short hand for
#notifications = Notification.find(:all, :conditions => ['expires_at > ?', Time.now])
notif = Notification.find(:all, cookie[0].to_i)
#notifications.delete(notif[0]) if not notif.empty?
cookie is an id of a notification stored into cookies.
this is in an iteration, that removes notifications that the user doesn't want to see.
thanks! =)

If this is an array of activerecord objects, you could delete from the database like this.
Notification.delete_all(:id => cookie[0].to_i)
If this is just an array, then you can use the delete if
#notifications.delete_if{|x| x == cookie[0].to_i}

Now you could just use the delete_at( index ) method:
array = ['item0', 'item1', 2, 3]
array.delete_at 1
# => "item1"
array.delete_at 2
# => 3
array
# => ["item0", 3]
You could do the same with slice!( index ).
Note: delete_at is a mutator method even if it doesn't end in !, so don't rely on its return value, it will only be the deleted item.
Reference:
http://ruby-doc.org/core-2.2.0/Array.html#method-i-delete_at

Related

Using primary keys as index for active record reads, Rails

When I use users=User.where(...)
I can use users.find(id) to find by it's id
I want to use a hash such so that I can use users[id] as a means of searching, where the id becomes the index of the hash.
How do I do this?
I have tried:
users.to_a.map(&:serializable_hash)
users.map(&:attributes)
users.map { |r| r.attributes.symbolize_keys }
None of these worked in turning the primary key into the index
To convert any Enumerable into a Hash, you can use index_by from ActiveSupport (activesupport/lib/active_support/core_ext/enumerable.rb)
users = User.where(...)
users.index_by(&:id)
# => { 1 => <User ...>, 2 => <User ...>, ...}
# note the difference between 'index_by' and 'group_by' where the latter will return an array of a single User for each id
users.group_by(&:id)
# => { 1 => [<User ...>], 2 => [<User ...>], ...}
As ActiveRecord::Relation includes the Enumerable module in its ancestors chain (you can check by ActiveRecord::Relation.ancestors.include? Enumerable), you can use any Enumerable instance methods on any ActiveRecord::Relation object.
For the solution to your specific need
indexed_users = [] # holds users on index as id
users.each {|u| indexed_users[u.id] = u.attributes }
Also converting id as index is not a good idea as the array size may go out of control if id become bigger like thousands or so and ids are not sequential. like
users = [<id: 1>, <id:200>] will result in array with size of 201.
Updated to get hash is as key
users.map(&:attributes).group_by { |attr| attr[:id] }

How can .where accept an array without braces?

I'm not sure how is this implemented, when you do something like:
Model.where(["subjects = ?", 1])
Rails allows you to omit the braces:
Model.where("subjects = ?", 1)
I know this is possible with hashes, but how is it possible so you can pass ANY number of arguments (you can have 100 question marks if you want) and for Rails to still interpret this as an array?
In Ruby a method can accept splat arguments.
def foo(*a)
a
end
foo('bar', 'baz')
# => ["bar", "baz"]
The splat gathers up any remaining arguments. You can even use it with regular arguments:
def foo(a, *b)
b
end
foo('bar', 'baz')
# => ["baz"]
You can even do something like:
def foo(*a)
a.length == 1 && a.first.is_a?(Array) ? a.first : a
end
Now calling foo('bar', 'baz') and foo(['bar', 'baz']) have the same return value.
However if what you want is a WHERE condition where the value can be one of many possible values you would write it like so:
Model.where(foo: [1, 2, 3, 5])
Which would create a WHERE models.foo IN (1,2,3,5) clause.
From the Docs
Model.where(array)
If an array is passed, then the first element of the array is treated as a template, and the remaining elements are inserted into the template to generate the condition. Active Record takes care of building the query to avoid injection attacks, and will convert from the ruby type to the database type where needed. Elements are inserted into the string in the order in which they appear.
User.where(["name = ? and email = ?", "Joe", "joe#example.com"])
# SELECT * FROM users WHERE name = 'Joe' AND email = 'joe#example.com';

How can I get the number of instances of a tag element with "id='foo'" using Watir?

How can I get the number of instances of a tag element with id='foo' using Watir?
I have this:
b = Watir::Browser.new
b.a(:id => 'foo')
How then do I get the number of instances and access via an index, like this:
b.a(:id => 'foo', :index => $i) #Here, $i is a variable in a loop
In pseudocode I'm essentially trying to do this:
num = "number of a tags with id foo"
while $i less than num do
put b.a(:id => 'foo', :index => $i).text into an array
end
I know how to do everything above EXCEPT finding num.
If you want to know how many matches there are, you need to get an element collection (not just an element). A collection is retrieved by pluralizing the element method - ie as.
b.as(:id => 'foo')
#=> <Watir::AnchorCollection>
From the collection, you can use length (or count) to find the number of instances:
b.as(:id => 'foo').length
Note that the element collection is Enumerable. This means you do not need to use a while loop and manual track the current index and total elements. For example, using each, you can simply write:
b.as(:id => 'foo').each do |a|
puts a.text
end
Below code should work for you:
arr = Array.new
b.as(:id => 'foo').each { |a| arr.push a}

Searching from a range of ids in ActiveRecord

How can I do something like this in range?
User.find(14000..14500)
I need to choose a certain range of Users starting and finishing on specifics ids.
You can use the where method:
User.where(id: 14000..14500)
Explanation
The where method here receives a hash argument in its shortened form, where the value for the id key is a Range.
You can do it like this too:
User.find_by_id(14000..14500)
Try this also
User.find((start..end).to_a)
Ex -
User.find((14000..14500).to_a)
You can use range definition for scoped:
User.find(1) # returns the object for ID = 1
User.find([1])
User.find(1, 2, 9) # returns an array for objects with IDs in (1, 2, 9)
User.find([1, 2, 9])
User.scoped(:conditions => { :id => 1..9})

Verifying if an object is in an array of objects in Rails

I'm doing this:
#snippets = Snippet.find :all, :conditions => { :user_id => session[:user_id] }
#snippets.each do |snippet|
snippet.tags.each do |tag|
#tags.push tag
end
end
But if a snippets has the same tag two time, it'll push the object twice.
I want to do something like if #tags.in_object(tag)[...]
Would it be possible? Thanks!
I think there are 2 ways to go about it to get a faster result.
1) Add a condition to your find statement ( in MySQL DISTINCT ). This will return only unique result. DBs in general do much better jobs than regular code at getting results.
2) Instead if testing each time with include, why don't you do uniq after you populate your array.
here is example code
ar = []
data = []
#get some radom sample data
100.times do
data << ((rand*10).to_i)
end
# populate your result array
# 3 ways to do it.
# 1) you can modify your original array with
data.uniq!
# 2) you can populate another array with your unique data
# this doesn't modify your original array
ar.flatten << data.uniq
# 3) you can run a loop if you want to do some sort of additional processing
data.each do |i|
i = i.to_s + "some text" # do whatever you need here
ar << i
end
Depending on the situation you may use either.
But running include on each item in the loop is not the fastest thing IMHO
Good luck
Another way would be to simply concat the #tags and snippet.tags arrays and then strip it of duplicates.
#snippets.each do |snippet|
#tags.concat(snippet.tags)
end
#tags.uniq!
I'm assuming #tags is an Array instance.
Array#include? tests if an object is already included in an array. This uses the == operator, which in ActiveRecord tests for the same instance or another instance of the same type having the same id.
Alternatively, you may be able to use a Set instead of an Array. This will guarantee that no duplicates get added, but is unordered.
You can probably add a group to the query:
Snippet.find :all, :conditions => { :user_id => session[:user_id] }, :group => "tag.name"
Group will depend on how your tag data works, of course.
Or use uniq:
#tags << snippet.tags.uniq

Resources