inserting into an array rails 3 - ruby-on-rails

I have a record and I want to inset it inside and array and later access it.
users = User.all
results = []
users.each do |user|
results << {:name => user.name, :email => user.email}
end
is results variable still an array ? If yes how can I get all the names alongwith email?

Your example would create an array results filled with hashes containing each users name and email.
You could access it in several ways, the easiest of which is a simple loop:
results.each do |result|
name = result[:name]
email = result[:email]
end
You can also access individual items directly like so:
first_result_name = results[0][:name]
but be careful of trying to access results that may not be there.
Arrays
Hashes
But I have to ask, why do you want to do this? There's no gain from assigning all the Users name and emails to an array, User.all is no different really in functionality.

Yes, it's still an array. You can have what you want later for example with:
results.each do |result|
result[:name] # access to name
result[:email] # access to email
end

You just need one line to do it
results = users.collect{|user| {:name => user.name, :email => user.email}}

In a kind of unrelated way, your initial code could be rewritten as:
results = User.all.inject([]) do |array, user|
array << {:name => user.name, :email => user.email}
end
Given that "results" now contains this collection of hashes, if you want to print every user name and email you would do:
results.each do |user|
puts "#{user[:name]} #{user[:email]}"
end

Related

How do I loop through a model and save that to an array?

I have a mailer that checks for all users that meet a certain criteria.
If that criteria is true, I'm trying to do a do loop, and return the result into an array.
I'm then trying to use that to loop through that array and send an email to each email in the array.
I tried assigning the variable 'emails' to this array where I'm passing this code in
emails = [User.where(:state => 'Arizona').each]
Which isn't working because when I do the following.. the emails aren't sent
emails.each do |email|
new_request(email,row).deliver_now
end
Then I tried to do a loop and save those results to an variable
User.where(:state => 'Arizona').each do |u|
emails = u.email
end
Yet again, when I do this following code the emails aren't sent
emails.each do |email|
new_request(email,row).deliver_now
end
FYI - everything else is working just fine with the rest of my program, the emails are definitely going out fine when I don't use this code. For instance, if I do this:
emails = ['a#gmail.com','b#gmail.com']
the array works fine, and then I can do this..
emails.each do |email|
new_request(email,row).deliver_now
end
and the code email is sent to a#gmail.com and b#gmail.com. So again, the real question is, how do I loop through those users where that criteria is true, and save to an array like this so I can run this emails.each do code and get it work?
User.where(:state => 'Arizona').each do |u|
emails = u.email
end
In the above logic, in every iteration, the emails will be overwritten with the iteration email.
You have to insert the emails in an array to make the logic as expected.
emails = []
User.where(state: 'Arizona').each do |u|
emails << u.email # To insert the user email into the array
end
You can also try to debug the values in the array whenever you face issues in logic.
User.where(:state => 'Arizona').each do |u|
emails = u.email
p emails, "emails" # To check the value stored in the emails.
end
Just use pluck
User.where(:state => 'Arizona').pluck(:email)
=> ["a#gmail.com", "b#gmail.com"]

How to compare new data with existing in bd before save

Every time, when I'm getting the data from the API request, I require to compare and update records, if any changes was there.
for example i have saved User
user = User.first
user.name => 'name_one'
when i calling to api,api returns me User but name was cahnged to 'name_two'
so i need compare existing user with newly arrived and if name changed replace it
example of calling api
url= 'my api str'
result = Curl.get(url)
JSON.parse(result.body_str).each do |key, value|
value["commissions"].each do |k, v|
User.create(name: v["name"],etc... )
end
end
I will be glad for any suggestions.
You can also try the following:
u = User.first
u.name = "name_two"
u.name_changed? #=> true/false
u.name_was #=> "name_one" if it was "name_one"
These are called dirty method and very helpful for this kind of task.
Thanks
Try this code
u = User.first
u.name = "name_two"
u.save if u.changes.include?("name")
I believe you shall use active record's private method #read_attribute to compare current updated values with stores ones:
if send(:read_attribute, :attr) == self.attr
# value isn't changed
end
Additional info you can read here:
Validation from controller
You shall validate newly created record from controller:
v['name'] = 'User 1'
user = User.create(name: v['name'])
user.name # => # User 1

For array of ActiveRecord objects, return array of their attributes

#matched = [1, 2, 3]
Where each integer represents the id of an ActiveRecord object in the Inventory class. As a next step, I want to look at each of those objects and obtain the email of the parent User, but I'm not sure how to do it. Ideally I'd write something like:
Inventory.where(id: #matched).user.email
Because certainly, this statement would work if I only had a single id to look up. Since that doesn't work, I'm instead doing this
#email = []
#matched.each do |i|
#email << Inventory.find_by_id(i).user.email
end
Just wondering if there's an easier way.
Thanks!
If you only need the email addresses then you can use the pluck method:
Inventory.where(id: #matched).joins(:user).pluck("users.email")
class Inventory
def self.with_ids(ids)
sql = #matched.map{|id| "id = #{id}"}.join(" OR ")
where(sql)
end
def parent_email
user.email
end
end
Inventory.with_ids(#matched).map(&:parent_email)

Can I use AR object as hash key or should I use object_id instead

Because of Ruby awesomeness it is possible to use any object as key
document = Document.find 1
o = Hash.new
o[1] = true
o[:coool] = 'it is'
o[document] = true
# an it works
o[document]
#=> true
but just because it is possible doesn't mean is good practice
However I have situation where in my controller I need to set something similar, so I can loop trough it in view
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user] ||= Array.new
#user_with_things[thing.user] << thing.id
end
#view
- #users_with_things.each do |user, thing_ids|
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]", :'data-user-type' => user.type }
The reason why I want to do it this way is because I don't want to call from my view User.find_by_id (want to make it clean)
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user.id] ||= Array.new
#user_with_things[thing.user.id] << thing.id
end
#view
- #users_with_things.each do |user_id, thing_ids|
- user = User.find user_id
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]", :'data-user-type' => user.type }
So my 1st question is: is it ok to use ActiveRecord object as Hash key in situation like this
I can imagine several scenarios where this may go wrong (sessions, when object changes in model and so on) however this is just for rendering in a view
Alternative !
so this is one way to do it, the other may be like this
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user.object_id] ||= Array.new
#user_with_things[thing.user.object_id] << thing.id
end
#view
- #users_with_things.each do |user_object_id, thing_ids|
- user = ObjectSpace._id2ref(user_object_id) #this will find user object from object_id
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]"", :'data-user-type' => user.type }
...which is even more, hardcore. However it is way around if for some reason hash[ARobject] = :something would create big memory cluster for some reason
question 2 : is it good idea to do it this way ?
to be complete there is also another alternative and that is
# ...
#user_with_thing[ [thing.user.id, thing.user.type] ] << thing_id
# ...
so basically array object will be key
#user_with_thing[ [1, 'Admin'] ]
#=> [1,2,3]
I think to use a hash is a good way to organise in your situation. However, I would advise against using the user or to big an object as hash keys, simply because it renders your hash unreadable and because it is really only this sole object with it's object id that can be used as a key.
o = Object.new
h = { o => 'something' }
h[Object.new] #=> nil
In your situation, this may not be an issue, because you simply need to iterate it. But it may be a shot in the leg as soon as you want to do something else with that hash, or you have different instances of the same Active Record Data (which is very common in Rails applications, unless you are a really paying attention what gets loaded when). Besides that, I think it is good to stick by the widely used convention to use simple objects (strings, symbols) as hash keys to make your code readable and maintainable.
Maybe it would be best to keep a two-dimensional hash, like this:
#users_with_things = Things.accessible_by(some_curent_user_logic).inject({}) do |a, thing|
user_id = thing.user.id
a[user_id] ||= { :user => thing.user, :things => [] }
a[user_id][:thing] << thing
a
end
Then you can iterate over #users_with_things in your view like this:
#users_with_things.each do |user_id, values|
# values[:user] is the user, values[:things] the array of things

How to store the result of my algorithm?

I have an algorithm that searches through all of my sites users, finding those which share a common property with the user using the algorithm (by going to a certain page). It can find multiple users, each can have multiple shared properties. The algorithm works fine, in terms of finding the matches, but I'm having trouble working out how to store the data so that later I'll be able to use each unit of information. I need to be able to access both the found users, and each of the respective shared properties, so I can't just build a string. This is an example of the output, being run from the perspective of user 1:
user 4
sharedproperty3
sharedproperty6
user 6
sharedproperty6
sharedproperty10
shareproperty11
What do I need to do to be able to store this data, and have access to any bit of it for further manipulation? I was thinking of a hash of a hash, but I can't really wrap my head around it. I'm pretty new to programming, and Ruby in particular. Thanks for reading!
EDIT - Here's the code. I'm fully expecting this to be the most incorrect way to do this, but it's my first try so be gentle :)
So if I'm understanding you guys correctly, instead of adding the interests to a string, I should be creating an array or a hash, adding each interest as I find it, then storing each of these in an array or hash? Thanks so much for the help.
def getMatchedUsers
matched_user_html = nil
combined_properties = nil
online_user_list = User.logged_in.all
shared_interest = false
online_user_list.each do |n| # for every online user
combined_properties = nil
if n.email != current_user.email # that is not the current user
current_user.properties.each do |o| # go through all of the current users properties
n.properties.each do |p| # go through the online users properties
if p.interestname.eql?(o.interestname) # if the online users property matches the current user
shared_interest = true
if combined_properties == nil
combined_properties = o.interestname
else
combined_properties = combined_properties + ", " + o.interestname
end
end
end
if shared_interest == true
matched_user_html = n.actualname + ": " + combined_properties
end
end
end
end
return matched_user_html
render :nothing => true
end
This returns an array of hashes with all users and their corresponding sharedproperties.
class User
def find_matching_users
returning Array.new do |matching_users|
self.logged_in.each do |other_user|
next if current_user == other_user # jump if current_user
# see http://ruby-doc.org/core/classes/Array.html#M002212 for more details on the & opreator
unless (common_properties = current_user.properties & other_user.properties).empty?
matching_users << { :user => other_user, :common_properties => common_properties }
end
end
end
end
end
In your view you can do something like this:
<%- current_user.find_matching_users.each do |matching_user| -%>
<%-# you can acccess the user with matching_user[:user] -%>
<%-# you can acccess the common properties with matching_user[:common_properties] -%>
<%- end -%>
You can use a hash table with the key being the user object and the value being an array of the shared properties . This is assuming that you first need to do a lookup based on the user .
Something like this :
#user_results = { user1 => [sharedproperty3,sharedproperty7] , user2 => [sharedproperty10,sharedproperty11,sharedproperty12]}
You can then acces the values like :
#user_results[user1]
or you can also iterate over all the keys using #user_results.keys

Resources