Ruby on Rails / Ruby: Populating Database With Usernames In A File - ruby-on-rails

I am trying to create users by populating the database with names in a file called names.rb which lives in the same place as seeds.rb. I am a ruby on rails / ruby newbie so please forgive me if this seems like a simple task. I keep getting the error: Cannot Load File names.rb. I am trying to do this by reading each line in the names.rb file and passing the content to the reiteration block (see below). How do I make sure that each line, for example John Kanye, Matthew Richards, etc. creates a new user with that name? Any help would be appreciated.
seeds.rb
require "names.rb"
File.open("names.rb").each { |line| puts line }
Name = line
User.create!(name: "Michael Princeton",
email: "michaelprinceton#gmail.com",
password: "foobar",
password_confirmation: "foobar",
admin: true)
5.times do |n|
name = Name
email = "example-#{n+1}#example.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
end
names.rb
John Kanye
Matthew Richards
Mary Mary
Mike Jacobs
etc

Rename the file to names.txt, since it is not Ruby code. Then do something like this:
User.create!(
name: "Michael Princeton",
email: "michaelprinceton#gmail.com",
password: "foobar",
password_confirmation: "foobar",
admin: true
)
File.foreach('db/names.txt').with_index do |name, line_number|
User.create!(
name: name,
email: "example-#{line_number+1}#example.org",
password: 'foobar',
password_confirmation: 'foobar'
)
end

Well there's a number of problems. It's clear you don't have a firm grasp ruby yet. I highly suggest you find a tutorial or book that starts from the very beginning. That said ..
The names.rb doesn't contain ruby code, it's a text file. The file extension .txtis used for plain text, so rename the file to names.txt.
It doesn't make sense to require a text file. When you require a ruby file, it interprets and runs the code in that file. names.txt does not contain ruby code. The fix is to delete that line.
Next, it reads the lines one at a time, and prints to standard output. Then the code attempts to set the constant Name to the block variable line which is now out of scope. It proceeds to create an admin user and five other users in a loop. None of this code accomplishes your goal, so you prolly copy/pasted it from somewhere without understanding it. We've come full-circle to my suggestion to invest time in learning ruby.
What you are looking for is something like:
File.open('names.txt').each_line do |line|
User.create(name: line.strip)
end
Learning by doing is wonderful, but you should start with a solid basis.

Related

Ruby on Rails Tutorial: Defining a hash with symbol keys

Regarding the exercises in Michael Hartl's RoR Tutorial in lesson 4.3.3 (Hashes & Symbols):
"Define a hash with symbol keys corresponding to name, email, and a “password digest”, and values equal to your name, your email address, and a random string of 16 lower-case letters."
I am hoping to get some input and/or alternative & 'better' solutions to this (or at least some criticism regarding my solution).
def my_hash
a = ('a'..'z').to_a.shuffle[0..15].join
b = { name: "John", email: "johndoe#gmail.com", password: a }
return b
end
puts my_hash
(Yes I realize this is a very simple exercise and apologize if it has been asked before.)
There are many 2 improvements could be made:
Use Array#sample to get random letters (it has an advantage: the letter might in fact repeat in the password, while shuffle[0..15] will return 16 distinct letters);
Avoid redundant local variables and especially return.
Here you go:
def my_hash
{
name: "John",
email: "johndoe#gmail.com",
password: ('a'..'z').to_a.sample(16).join
}
end
puts my_hash
Bonus:
I accidentaly found the third glitch in the original code. It should probably be:
def my_hash
{
name: "Brandon",
email: "brandon.elder#gmail.com",
password: ('a'..'z').to_a.sample(16).join
}
end
:)

Ruby - passing block inside the function parenthesis

I have recently started to learn Ruby on Rails and it is really weird to get used to the syntax of Ruby.
I decided to go with all the parenthesis (that I know from other languages) that can be placed and I got stuck:
test "invalid signup information" do
get signup_path
assert_no_difference("User.count", {
user_params = { user: {
name: "",
email: "foo#invalid",
password: "foo",
password_confirmation: "bar"
}}
post(user_path, {params: user_params})
})
end
I want to pass a block into the assert_no_difference and somehow it is showing me an error during my tests. It started to show it after I places the definition of user_params. As far as I read some websites the syntax is OK, so what might be going wrong?
There's two general forms for passing in blocks. The long-form way is to use do ... end:
assert_no_difference('User.count') do
# ...
end
There's also the curly brace version:
assert_no_difference('User.count') {
# ...
}
Note that the curly brace style is generally reserved for single line operations, like this:
assert_no_difference('User.count') { post(...) }
For multi-line you generally want to use do...end since it's easier to spot. The When in Rome principle applies here, so you may need to shed some of your expectations in order to do things the Ruby way.
What you're doing wrong is passing in an argument that's presumed to be a Hash, but as it contains arbitrary code that's invalid. Unlike JavaScript the block is defined outside of the arguments to function call.
Cleaning up your code yields this:
test "invalid signup information" do
get signup_path
assert_no_difference("User.count") do
post(user_path,
params: {
user: {
name: "",
email: "foo#invalid",
password: "foo",
password_confirmation: "bar"
}
}
)
end
end
Note you can supply the arguments inline, plus any hash-style arguments specified as the last argument in a method call does not need its curly braces, they're strictly optional and usually best omitted.

Rails console - TypeError: can't cast Hash to string

A little background first, I was able to get the - Angular/Rails project working on local
I went to change the user/password in sqlite3 and here are the steps that I took
rails c
a = User.find(1)
a.name = "myName"
a.password_digest = "mySurName"
a.save
Great, it worked! NOT
Well, kind of, but the Angular app is looking for a password that looks something like this - $2a$10$TrTjNCWr5KlwW2h9aJr45u8MwLDo2ErEFQp1/ixc.8KW...
After doing some digging, I found a stackoverflow answer
Followed by me trying to do the following:
a = User.find(1)
filters = Rails.application.config.filter_parameters
f = ActionDispatch::Http::ParameterFilter.new filters
b = f.filter :password_digest => 'mySurName'
a.password_digest = b
Which results in an error that is in the subject line of this post - TypeError: can't cast Hash to string, followed by (0.1ms) rollback transaction and tons of lines of references to .rb files
So, my ultimate question is, how do I update a record that has a filter on a password field, while using rails console?
Thanks in advance
You should read up on password hashing and storage, your password should never be stored as plaintext. Just a hunch, try this instead:
a = User.find(1)
a.name = "whatever"
a.password = "something"
a.save
In devise (and probably others) a password setter is defined for the User model which automatically stores the hash of the password in the password_digest column.
OK, while reading another post to something that was somewhat unrelated - here's the answer:
a = User.new(:name => "Luke", :password => "Skywalker", :password_confirmation => "Skywalker")
a.save
Which creates something like this:
password_digest: "$2a$10$OPlc1rCZscqPkFYSp10NQeTmDRNs1iuv6D0VLAKk8sXu..."

Rake data import task isn't updating correctly

I have a .txt file full of attributes like so:
"12345", "1", "Kent"
"67890", "1", "New Castle"
I need this to update my County model, and so I have this rake task:
namespace :data do
desc "import data from files to database"
task :import => :environment do
file = File.open(File.join(Rails.root, "lib", "tasks", "counties.txt"), "r")
file.each do |line|
attrs = line.split(", ")
c = County.find_or_initialize_by_number(attrs[0])
c.state_id = attrs[1]
c.name = attrs[2]
c.save!
end
end
end
All seems to be well, but when I check in the console to make sure it was imported correctly, I get this:
#<County id: 2, name: nil, number: 0, state_id: 0, created_at: "2013-08-04 17:44:11", updated_at: "2013-08-04 17:44:11">
I know that it's actually importing something, because it has created exactly the right number of County records, but it's not actually updating the attributes correctly. I'm sure I'm missing something very obvious but I can't find it!
Assumption: County.number is defined as an integer field.
attrs[0] after your line.split comes out to be "\"12345\"" (a string). The find_by method defaults the lookup key to 0 (integer) given that it's looking up an integer field (number). This would explain why your code works when you manually strip out the quotation marks from the first data column in the text file.
Based on this root cause, there could be multiple ways to resolve your issue. Here's an ugly way:
c = County.find_or_initialize_by_number(Integer(attrs[0].gsub(/\"/, '')))
Ideally, I would trim out (or gsub) quotes when doing the line text split.

Comparing one array against another in rails

I am using the 'contacts' gem in rails to retrieve a users contacts from their mail application. It returns the contacts like so:
["person name", "personemail#example.com"], ["person name", "personemail#example.com"], ["person name", "personemail#example.com"] etc...
I want to compare this list to the Users already signed up for my site
Users.find(:all) returns:
[#<User id: 11, login: "examplelogin", email: "example#example.com">, #<User id: 12, login: "examplelogin", email: "example#example.com">, etc... ]
What is the best way to go about comparing the gmail contact emails to the User emails and displaying only the ones that are a match?
I was thinking something like:
#contacts = Contacts::Gmail[params[:from]].new(params[:login], params[:password]).contacts
#contacts.each do |c|
#email = c[1]
#user = Users.find_by_email(#email)
end
Which would presumably only return the users where there was a match. I feel like there must be a better way to go about this that I am not considering. Any suggestions?
#users = Users.find_all_by_email(#contacts.collect{|contact| contact[1]})
edit:
What you had before would perform a find for each contact and leave you only with the result of the last query, either a user or not depending on whether one existed with this email. This performs one query and returns an array of all successful matches:
where 'users'.'email' in array_of_email_addresses.

Resources