Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamesDullaghan/5542473 to your computer and use it in GitHub Desktop.
Save JamesDullaghan/5542473 to your computer and use it in GitHub Desktop.
Schneems UT Rails Notes Spreadsheet to db, dealing with nil, modules

#Schneems UT on Rails course notes

  • Spreadsheet to DB
  • Dealing with nil
  • Modules

Spreadsheet to Database - Schneems

We need a csv file

We need to parse using CSV

require 'csv'

CSV.foreach('path/to/products.csv') do |row|
  puts row.inspect
end

=> ["HD Electric Amplifier", "269"]
   ["Video Audible System", "135"]
   ["Tag Direct System", "283"]
   ["Output GPS Kit", "985"]
  • This is going to call .foreach on the path of the CSV
  • Then for each row we increment through we are going to puts whatever is returned from row.inspect.

Now we need to add to DB with ActiveRecord

CSV.foreach('path/to/products.csv') do |row|
  name  = row[0]
  price = row[1].to_i
  Product.create(name: name, price: price)
end
  • Here we can use the bracket syntax
  • Pull out the first element from the row array and assigning that to a variable of name
  • Pull out the second element from the row array and assign it to the variable of price
  • Then we run Product.create(:name name, :price price), where the name variable is assigned to the :name key and the price variable is assigned to the :price key.

Put a script inside of a Rake task that we can use inside of a Ruby project, as well as a Rails project

Rake is a multipurpose tool for running scripts

list rake tasks

rake -T

rake about
rake assets:clean
rake assets:precompile
rake db:create
rake db:drop
rake db:fixtures:load
rake db:migrate
rake db:migrate:status
rake db:rollback
rake db:schema:dump

Create your own rake tasks

Lives inside of lib/tasks/import.rake

name it something.rake we are going to start out declaring a namespace This is so we don't have conflicting named rake tasks

namespace :import do
end

Once we've done that, we can then add a task into the rakefile

namespace :import do
  tasks :data => :environment do
  end
end

Before we run the data tasks, we need to run the environment task Environment is a rake task that rails gives us that loads models, and everything that we would normally be able to use when we have a rails console open

we can also add an optional description to our rake tasks

namespace :import do
  desc "imports data from a csv file"
  task :data => :environment do

  end
end

This is the description that is seen when we run rake -T

namespace :import do
  desc "imports data from a csv file"
  task :data => :environment do
    require 'csv'
    CSV.foreach('path/to/products.csv') do |row|
      name  = row[0]
      price = row[1].to_i
      Product.create(name: name, price: price)
    end
  end
end

Now that we have all this setup we need to add some code. We can just take that earlier code and paste it in..

Now we have our rake task built, how do we run it?

we can call $rake import:data This is pretty self explainatory

  • import comes from the namespace, :import
  • data comes from the task name, :data

Put one off scripts into rake taks (things you just need to run once, but aren't tied into your application all of the time (things you will run yourself))

Dealing with nil

user = User.where(:name => 'richard').first
puts user.name
=> richard

If someone has removed their account, or a name you are looking for doesn't exist yet, you will be returned a NoMethodError: undefined method 'name' for nil:NilClass

=> NoMethodError: undefined method 'name' for nil:NilClass

nil is our constant enemy - lol we have to be constantly concerned wether we are getting values back from functions

def number_greater_than_twenty_six(number)
  if number > 26
    "Number is greater than 26"
  else
    "Nope"
  end
end

number_greater_than_twenty_six(88)
=> "Number is greater than 26"

number_greater_than_twenty_six(2)
=> "Nope"

number_greater_than_twenty_six(nil)
=> NoMethodError: undefined method '>' for nil:NilClass

nil has a major weakness we can use to combat it nil behaves like a false in boolean operators

&& or || == Boolean operators
&& == Logical AND
|| == Logical OR

Typically used with if statements We can protect against nil with those

Or logic

I will be happy if I get burger or fries True = yes you got burger True = yes you got fries

puts true || true
=> true

If you got burgers OR fries, you are going to be happy 1st = yes you got burger 2nd = No you didn't get fries

puts true || false
=> true

If you got burgers OR fries, you are still going to be happy.

One true in a chain of OR will return true

puts false || false || false || true
=> true

nil behaves like false

puts nil || nil || nil || true
=> true

AND logic

Logical AND

I will be happy if I get burger AND fries 1st = I did/didn't get burger 2nd = I did/didn't get fries

puts true && true
=> true

I am happy because I got burger AND fries

put true && false
=> false

I am NOT happy because I got burger, but DIDN'T get fries One false in a chain of && will always return false

puts true && true && true && false
=> false

AND IS A DEMAND Because of this, Ruby will always return false the first time it runs into a false, when evaluating a series of &&/AND's

puts true && true && true && false

Checks first, returns true, then second, then third, then last returns false, so return now and it returns false Ruby never needs to evaluate the rest of those conditions.

nil behaves likes false - Same as above

def number_greater_than_twenty_six(number)
  if number > 26
    "Number is greater than 26"
  else
    "Nope"
  end
end

number_greater_than_twenty_six(nil)
=> NoMethodError

puts nil > 26
=> NoMethodError

puts nil && nil > 26
=> nil

Because nil is evaluated as false, it doesn't even make it to the nil > 26 It just returns nil, which is false, which in turn returns else or "Nope".

Logic Check

if true
  puts "Hello world"
else
  puts "nope"
end

=> "Hello world"

What about BANG true (bang negates, or does the opposite)

if !true
  puts "Hello world"
else
  puts "nope"
end

=> "nope"

If we do just puts user.name and there is no user with that specific name it will return a NoMethodError

user = User.where(:name => 'richard').first
puts user.name
=> NoMethodError

We can get around this by

user = User.where(:name => 'richard').first
if user
  puts user.name
end
=>

We can use that knowledge that a nil value is going to behave like false, to protect our calling of user.name If user exists (if user) puts user.name

We can check it more explicitly by doing

user = User.where(:name => 'richard').first
if !user.nil?
  puts user.name
end
=>

If not user.nil. If the user is not nil, puts user.name

What about empty arrays? Sometimes we pull empty arrays from the db

user = User.where(:name => 'richard')
if !users.empty?
  # ...
end

Here we have used two different operators, but in rails we can just use the .blank operator

nil.blank?
=> true
[].blank?
=> true
"".blank?
=> true
{}.blank?
=> true
"hello there".blank?
=> false

instead of using .nil? or .empty? we can use .blank? .blank? is part of ActiveSupport

user = User.where(:name => 'richard').first
if !user.blank?
  puts user.name
end
=> ???

user = User.where(:name => 'richard')
if !users.blank?
  users.each { |u| puts u.name }
end
=> ???

Using !user.blank?(user is not blank => return true or false) is still confusing because it is doing the opposite of seeing if it is blank. There is a more simple method to keep things more foreward.

user = User.where(:name => 'richard')
if users.present?
  users.each { |u| puts u.name }
end

ActiveSupport also gives us try

user = User.where(:name => 'richard').first
puts user.try(:name)
=> "Richard"

nil.try(:name)
=> nil

Ruby is flexible with if. Don't need to use end if 'if' is inline

user = User.where(:name => 'richard').first
puts user.name if user.present?

Also, we have the ability to use unless. Unless is the opposite of 'if'

user = User.where(:name => 'richard')
puts user.name unless user.blank?

=> ???

Unless is beautiful, please do not use unless with more than one arguement. Makes way more sense to use 'if'

NONO
user = User.where(:name => 'richard').first
puts user.name unless user.blank? ||
                      user.name == 'richard' &&
                      user.movie == 'zoolander'

=> ???

One last logic trick Scenario with find or create

user = User.where(:name => 'richard').first
puts user
=> nil

If the record exists find it, if it doesn't create it!

puts nil || "Hello"
=> "Hello"

nil is falsey, so it continues to look for a truthey because of OR ||

puts "foo" || "hello"
=> "foo"

Result is going to return foo because foo is truthey so it will return immediately

We can use this behavior

user = User.where(:name => 'richard').first
user = user || User.create(:name => 'richard')
puts user
=> #<User id: 2, name: 'richard' >

Find a user where the name is richard, return first record. if a user exists, return immediately if a user does not exist, go to the next statement in our or chain, create a user with the :name => 'richard' puts user that returned immediately, or user that was created

Same thing with different syntax

number = 27
number ||= 28
puts number
=> 27

Number is 27, which is not false or nil, do we check the next statement? No, return immediately. Second statement is 27 or == 28

number = nil
number ||= 28
puts number
=> 28

check the next statement because nil is false number is now equal to 28 because 28 is not nil or false

So if I do

user = User.where(:name => 'richard').first
user = user || User.create(:name => 'richard')
puts user
=> #<User>

SAME THING AS

user = User.where(:name => 'richard').first
user ||= User.create(:name => 'richard')
puts user
=> #<User>

To recap we can deal with nil by

&& trick
if and blank?
if and present?
use the ||= (or equals)

Modules

Modules are meant to mix in methods into ruby code

class Dog
  def bark
    puts 'woof'
  end
end

class Puppy < Dog
end

puts Puppy.new.bark
=> 'woof'

What if we wanted to share methods across multiple classes

module AnnoyingAnimal
  def sit
    puts "*chews on shoes*"
  end
end

class Puppy < Dog
  include AnnoyingAnimal
end

puts Puppy.new.sit
=> "*chews on shoes*"

Alternately, reuse

class Kitty < Cat
  include AnnoyingAnimal
end

puts Kitty.new.sit
=> "*chews on shoes*"

REAL EXAMPLE Enumerable module - Used by array

Modules cannot be instantiated Classes can be instantiated

module AnnoyingAnimal
  def sit
    puts "*chews on shoes*"
  end
end

AnnoyingAnimal.new
=> NoMethodError

Include gives us an instance method(a method on the instance)

module AnnoyingAnimal
  def sit
    puts "*chews on shoes*"
  end
end

class Puppy < Dog
  include AnnoyingAnimal
end

puts Puppy.new.sit
=> '*chews on shoes*'

Extend gives us class method (a method on the class)

module AnnoyingAnimal
  def sit
    puts "*chews on shoes*"
  end
end

class Puppy < Dog
  extend AnnoyingAnimal
end

puts Puppy.sit
=> '*chews on shoes*'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment