Creating a user from an array of emails - ruby-on-rails

Im creating an api to create a new userS(plural) from an array of emails.
We are assuming that there are no validations other than user requires an email. So all i need is an email to create a user.
Reason i'm doing this is because i'm creating an API.
How do i create users from an array of emails?
Here is the array. I actually have real emails but for this example i will make them up.
# => [
# [0] "email1#example.com.au",
# [1] "email2#example.com.au",
# [2] "email3#example.com",
# [3] "email4#example.com.au",
# [4] "email5#example.com.au"
# ]
To create a user it's just the typical way
User.new(email: 123#example.com)
Thanks in advance for any help.

To save records based on your array, you will want to store that array in a variable (remember that in Ruby, everything is an object). Let's say you have:
emails = ["email1#example.com.au",
"email2#example.com.au",
"email3#example.com",
"email4#example.com.au",
"email5#example.com.au"]
From there you can write a loop that iterates over your lovely array and creates a User for each array item you declared:
emails.each do |e|
User.create(email: e)
end
User.new will not save the records, so please use User.create.

If you just want to save records basing on the emails list(which is an array basing on your description), you just need to do everything like #l0010o0001l said(I love this nickname! :) ).
But in my opinion, you could do something more if this api will be provided to others.
The first thing is that you should format the email address with all words in lower-case before you save them. This may do great help whenever save new records or maintain old records. Just like:
emails.each do |email|
User.create(email: email.downcase)
end
Then you need to present result to the one who calls the api. just like: if all the email list was created successfully you can respond with the records amount created successfully. And if some records can not be created(format error, record has existed .etc) you should respond with the error info (you may need to use user.errors.full_messages to get error messages).

The way to do this is somethign like
user_emails.each do |user_email|
User.create(email: user_emails )
end

Related

Rails - conditional deliver_now based on the content returned by the mailer method

How can I deliver_now conditionally based on the content of the data returned by the mailer method?
I have a Mailer that is sent via a loop through a list of users, like so:
users.each do |u|
AbcMailer.with(user_id: u.user_id).abc_report.deliver_now
end
The list of users that should receive the mailer (users in the loop) lives in ActiveRecord, and all the users' actual data lives in an external MySql DB.
The abc_report method in the AbcMailer class makes some queries to the MySql DB and returns a bunch of info for each user, which is then inserted into an html.erb email template, and delivered now.
My issue is that I need to only deliver to some of those users, because in the DB, one of the pieces of info that comes back is whether the user is active or not. So I would like to only deliver_now if the user has active = 1. But I can't find any examples of unchaining these methods to do what I want.
When I just do AbcMailer.with(user_id: u.user_id).abc_report, what it returns is actually the filled-out html.erb template already. When I do AbcMailer.with(user_id: u.user_id) by itself, it returns #<ActionMailer::Parameterized::Mailer:0x00007fdd43eb5528>.
Things I've Tried
I tried inserting a return if user["Active"] == 0 in the abc_report method but that obviously killed the entire loop rather than skipping to the next item, so I'm working under the assumption that the skip has to happen with a next in the actual loop itself, not in an external method being called.
I also found this which seems like a great solution in a plain Ruby context but because in this case, abc_report is automatically filling out and returning the AbcMailer html.erb template...I'm stumped on how I would get it to just return a boolean without killing the whole loop.
Assuming that you have active field of boolean type in users table and you want to send the emails to all active users.
users.each do |u|
AbcMailer.with(user_id: u.user_id).abc_report.deliver_now if u.active
end
you can add any other condition on this as well.
Add this to user.rb
scope :active, -> {
where(active: 1)
}
Now in your mailer
Users.active.each do |user|
AbcMailer.with(user_id: user.user_id).abc_report.deliver_now
end
This way you have to get less data from the database, resulting in a faster query.

Ruby on Rails action on all objects in an array?

Let's say I have a list of emails in an array, let's say ~2000 emails.
emails = ["AllenXiang#boyaa.com", "2dlogic#gmail.com", "support#KalromSystems.com", "kangisupport#helendorongroup.com", "James#APPCRASHCOURSE.COM", "James#appcrashcourse.com", "SpartanAppsUK#gmail.com"]
Let's say I theoretically want to get the emails site name. So I want to do emails.each do |email| puts email.split("#")[1]
Which would get me each of the site names for the emails. But I'm curious, is there a faster way to get that out of the array?
Ideally I'd like to create an array.uniq that contains a unique list of every site linked to the emails. I could do this manually, but I'm wondering if there's a quicker way to do this on the array itself (the array I actually have is ~2 million emails in length).
What you're creating isn't really an array, which cares about order and doesn't care about uniqueness. You want a Set, which doesn't concern itself with order, but doesn't allow duplicates.
require 'set'
email_domains = Set.new
emails.each do |email|
email_domains.add email.split('#', 2).last
end
I prefer this solution
emails.map { |email| email.split('#').last }.uniq
Updated
Or this one
emails.collect { |email| email.split('#').last }.uniq

How to create a hash for all records created by a user?

In our Rails app, the user (or we on his behalf) load some data or even insert it manually using a crud.
After this step the user must validate all the configuration (the data) and "accept and agree" that it's all correct.
On a given day, the application will execute some tasks according the configuration.
Today, we already have a "freeze" flag, where we can prevent changes in the data, so the user cannot mess the things up...
But we also would like to do something like hash the data and say something like "your config is frozen and the hash is 34FE00...".
This would give the user a certain that the system is running with the configuration he approved.
How can we do that? There are 7 or 8 tables. The total of records created would be around 2k or 3k.
How to hash the data to detect changes after the approval? How would you do that?
I'm thinking about doing a find_by_user in each table, loop all records and use some fields (or all) to build a string and hash it at the end of the current loop.
After loop all tables, I would have 8 hash strings and would concatenate and hash them in a final hash.
How does it looks like? Any ideas?
Here's a possible implementation. Just define object as an Array of all the stuff you'd like to hash :
require 'digest/md5'
def validation_hash(object, len = 16)
Digest::MD5.hexdigest(object.to_json)[0,len]
end
puts validation_hash([Actor.first,Movie.first(5)])
# => 94eba93c0a8e92f8
# After changing a single character in the first Actors's biography :
# => 35f342d915d6be4e

how to store facebook friends to DB (newbie)

i'm creating a facebook-app for university project and i'm trying to store all my friends in the DB.
By using the API-syntax "me/friends" i get a facebook-respond looking like this:
{"data"=>[{"name"=>"Albert Einstein", "id"=>"11111111"}, {"name"=>"Max Mustermann", "id"=>"222222222"}, {"name"=>"Just Another Name", "id"=>"333333333"}]}
I believe its a json-object, but i'm not sure.
Question: How can i save the data, i need a DB with all the User-IDs of my friends.
Thx!
Edit:
Hey, this is what i have searched for. But i still get an error and don't know why.
My code:
def insert_1
fb_friends = rest_graph.get('me/friends')
fb_friends[:data].each do |f|
#friend = Model.new(:name => f["name"] )
#friend.save
end
end
I get an Heroku error (We're sorry, but something went wrong.)
You have two options -
Option 1-
You can create a friends table which will belong to users table. If a user has 200 friends, it will create 200 entries in friends table all belonging to the user via has_many-belongs_to relationship. For storing data, you just have to iterate over facebook friends hash and then save each of them separately
Pros : You can search for any friend separately.
Cons : There will be so many of friend entries. Saving them will take time, if somebody has many friends(say 500-700). Repeating entries will be created for mutual friends.
Options 2
You can add a friends column in your users table and declare this in your user.rb
serialize :friends
This way, you just have to pass a hash object to friends attribute of user table, and rails will save that in yaml format for you. When you will do #user.friends, rails will again convert that yaml formatted data to hash object and return it.
Pros : There will be only one query to save all users. You can iterate through this hash to show list of all friends.
Cons : You can't update them separately, you will update all together. Not good if you want to store some other information in relation to user's friends.
Update
as per your code example above
fb_friends = #your logic to get data as shown above.
fb_friends[:data].each do |f|
#friend = Friend.new(:name => f["name"],:fb_user_id => f["id"] )#creating Friend model obj.
#friend.save
end

What's the best way to validate multiple emails and handle errors in Rails?

In the current app I'm building I've got a textarea where a user will enter a comma-delimited list of email addresses.
I'm currently splitting the list into an array and then saving one by one. But if, say, I have this input...
blah#example.com, test#example, foo#example.com
... then blah#example.com will be saved, but saving test#example will fail. So I then need to remove blah#example.com from the comma-delimited string of values that I pass back to the textarea when I show the error that test#example isn't a valid email address.
Is there a better way to validate these on the server side and handle errors without getting fancy / ugly in the controller?
Thanks in Advance!
Assuming this is a model that has_many emails, and the email model uses :validate_email, you could do something like the following:
class Foo < ActiveRecord::Base
validate :must_not_have_invalid_addresses
...
def emails=(addresses)
#invalid_addresses = []
addresses.split(",").each do |address|
#invalid_addresses.push(address) unless emails.create({:address => address})
end
end
def must_not_have_invalid_addresses
errors.add_to_base("Some email addresses were invalid") unless #invalid_addresses.empty?
end
end
This provides a validation error + an array of the invalid email addresses which you can make accessible to your view if you like.
ruby has a split function (.each) described here and supports regular expressions as described here
as such, you'd split the string (using "," as your separator) and then use the regular expression to validate each e-mail.
You can put saving emails in transaction. Then if any save will fail, then all previos saves are canceled. In such case, validations can be done only on model layer.
I think it would be clear code, but for sure it isn't the fastest possible way (but using Ruby means you are not doing it in even fast way ;) )
If you have them in a variable called emails, perhaps something like this may work:
if valid_emails?(emails)
# then have your normal logic here
if #user.save
flash[:notice] .....
end
end
private
def valid_emails?(emails)
not emails.find {|email| email =~ /[\w\.%\+\-]+#(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2,}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)/i }.nil?
end
EDIT: actually you may just want to use this regular expression. It was taken from the restful-authentication plugin.

Resources