Iacutone.rb

coding and things

The Setter Method in a Rails Model

| Comments

At Fractured Atlas, we are trying to move away from the additional complexity of using callbacks. For example, let’s say we need to do something in a before_save callback such as lowercase a user’s email.

user.rb
1
2
3
4
5
before_save: lowercase_email

def lowercase_email
  self.email = self.email.downcase
end

How is this code implemented without using before_save? One method would be overriding the setter accessor.

user.rb
1
2
3
4
def email=(value)
 email = value.downcase
 super(email)
end

Now, when the email attribute is updated, my email setter method is called.

Currently, both implementations for downcasing an email are straightforward. However, as the application grows, the before_save callback is more difficult to test and maintain. The before_save is implicit and might have unexpected side effects. Here is a basic spec.

user_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
describe User do

  let(:user) { FactoryGirl.create(:user) }

  describe '#lowercase_email' do
    before { user.email = 'GNARLY@email.com' }

    it 'lowercases the email' do
      expect(user.lowercase_email).to eq 'gnarly@email.com'
    end
  end
end

Instead, let’s test the behavior of what we expect.

user_creation_spec.rb
1
2
3
4
5
6
7
8
9
10
11
describe 'User Creation' do
  let(:user) { FactoryGirl.create(:user) }

  describe ':email' do
    before { user.email = 'GNARLY@email.com' }

    'it returns a standardized email' do
      expect(user.email).to eq 'gnarly@email.com'
    end
  end
end

The first spec is directly testing the callback, whereas the latter spec is testing the behavior of the expected outcome. The latter spec is easier to reason about and change. This is an easy example, but as callbacks grow changing their behavior becomes more difficult. This is especially true if the callbacks are coupled with other models.

Helpful Links

What is the right way to override a setter method in Ruby on Rails?

Overwriting default accessors

Ruby's Fetch Method

| Comments

Checking for values in a Rails params hash is complicated. In this post we will use the #fetch method to ensure nil is not called on a params hash.

searches_helper.rb
1
2
3
  if params[:search][:organization_id].present?
    # do things
  end

The code above will call #present? on nil if params[:search][:organization_id] does not exist.

A better way to write the conditional:

searches_helper.rb
1
2
3
  if params[:search].present and params[:search][:organization_id].present?
    # do things
  end

Writing a similar conditional with #fetch:

searches_helper.rb
1
2
3
  if params.fetch(:search, {}).fetch(:organization_id, nil).present?
    # do things
  end

Let’s break this method down into simpler components:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  params = {}
  puts params.fetch(:search, {})
  // {}

  params[:search] = "searched!"
  puts params.fetch(:search, {})
  // "searched!"

  puts fetch(:organization_id, nil)
  // nil

  params[:organization_id] = 1
  puts params.fetch(:organization_id, nil)
  // 1

I like the ability to call #fetch with a default return value if one does not exist. This leads to better ways to handle nil or catch errors.

Swift Basics

| Comments

String Interpolation

1
2
3
4
5
var name = "Eric"

println("Hello, \(name)")

// "Hello, Eric"

Dictionaries

1
2
3
4
5
6
7
8
9
var response = ["id":14,"email":"test@email.com"]

let id = response["id"]

// 14

let email = response["email"]

// "test@email.com"

Tuples

Unnamed Tuples

1
2
3
4
5
6
7
8
9
10
11
var coordinates = (100, 999)

let (lat, lon) = coordinates

println("Latitude is \(lat)")

// "Latitude is 100"

println("Longtitude is \(lon)")

// Longitude is 999

Named Tuples

1
2
3
4
5
6
7
8
9
10
11
12
13
var response = (code: 200, message: "All good")

response.0
// 200

response.1
// "All good"

response.code
// 200

respsonse.message
// "All good"

Swift Classes

Creating a class

Person.swift
1
2
3
4
5
6
7
8
9
10
11
12
13

class Person: NSObject {
  var name: String
  var email: String
  var zip: Int

  init(name: String, email: String, zip: Int) {
    self.name = name
    self.email = email
    self.zip = zip
    super.init()
  }
}

Create data for Person Class

SampleData.swift
1
2
3
let personData = [
  Person(name: "Eric", email: "eric.iacutone@gmail.com", zip: 12345)
]

Instantiating Person Class

PersonViewController.swift
1
var person:Array = personData

Now, if you copy and paste the the files into a XCode Playground, you can call methods on your person object.

Playground.swift
1
2
3
4
5
person.count
// 1

person.first?.zip
// 12345

Enums

An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. - Swift docs

Use an enum when you need a consistent data value.

1
2
3
4
5
6
7
8
9
10
11
12
enum CountryType:String {
    case UnitedStates = "United States"
    case Spain = "Spain"

    init() {
      self = .UnitedStates
    }
}

var type = CountryType.UnitedStates.rawValue

// "United States"

Structs

A struct allows you to create a structured data type which provides storage of data using properties and extending its functionality via methods. -Tree House

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Person {
    var name: String
    var email: String
    var country: CountryType
}

var person = Person(name: "Eric", email: "eric.iacutone@gmail.com", country: CountryType.UnitedStates)

person.name

// "Eric"

person.country.rawValue

// "United States"

My Return to Blogging

The goal of this blog is to refine my writing skills. In order to fulfill this goal I will write about something interesting I learned on a weekly basis. I find that if I do not get into a routine, I will not fulfill my goal. So, every Friday after work I will post on this blog. I have no goals about the legth of posts, but to write something with clarity and thoughfulness.

Exceptions in Ruby

| Comments

I inherited some interesting code last week. A user has the ability to sign into the website with omniauth.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def num
  puts "Enter a number"
  num = gets.chomp.to_i

  if num == 3
      puts "It's a 3!"
      else
          raise "Wrong number, you entered a #{num}"
  end
end

def num2
  num
end

begin
  num2
rescue Exception => ex
  puts ex
end

Reference

Ruby Exception Class

Refactoring Client Side Validations

| Comments

I have been working on refactoring my client side JavaScript validations on an application. My tech lead gave me some illuminating tips on how to refactor my non-DRY code. Here is an example of the pre-refactored code.

_form.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<%= form_for(@order) do |f| %>
  <div class='your_info'>
    <h3>2. Your Information</h3>
    <div class="clearfix">
      <%= f.label :first_name, 'First name*' %>
      <div class="input">
        <%= f.text_field :first_name %>
        <span id="first_name_error"></span>
      </div>
      <div class="input">
        <%#= f.hidden_field :customer_id, value: current_user.id unless current_user.id == nil %>
      </div>
    </div>
    <div class="clearfix">
      <%= f.label :last_name, 'Last name*' %>
      <div class="input">
        <%= f.text_field :last_name %>
        <span id="last_name_error"></span>
      </div>
    </div>
    <div class="clearfix">
      <%= f.label :email, 'Email*' %>
      <div class="input">
        <%= f.text_field :email %>
        <span id="email_error"></span>
      </div>
    </div>
  </div>
  <%= f.submit "Submit your Order", class: 'btn btn-primary btn-lg', id: 'button', data: { confirm: "Place order?" } %>
<% end %>

So, let's start with this basic form and sprinkle it with some JQuery and Javascript for client side validations.

users.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Initial State for Form
$('.your_info').hide();

// validations
var first_name = $('input#order_first_name');
var last_name = $('input#order_last_name');
var email = $('input#order_email');

// event listeners
first_name.keyup(function(){
  validateFirstName();
});

last_name.keyup(function(){
  validateLastName();
});

email.keyup(function(){
  validateEmail();
});

function validateFirstName(){
  var first_name_val = first_name.val();
  if(first_name_val.length == 0) {
    first_name_error.show().text("First name needed.").addClass('error_class');
    return false;
  }
  else {
    first_name_error.hide();
    return true;
  }
}

function validateLastName(){
  var last_name_val = last_name.val();
  if(last_name_val.length == 0) {
    last_name_error.show().text("Last name needed.").addClass('error_class');
    return false;
  }
  else {
    last_name_error.hide();
    return true;
  }
}

function validateEmail(){
  var email_val = email.val();
  if(email_val.length == 0) {
    email_error.show().text("Email needed.").addClass('error_class');
    return false;
  }
  else {
    email_error.hide();
    return true;
  }
}

Clearly, this is not DRY and will easily get out of comtrol. However, using HTML data attributes solves this problem. Here is a good summary about data attributes by John Resig.

_form.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%= form_for(@order) do |f| %>
  <div class='your_info'>
    <h3>2. Your Information</h3>
    <div class="clearfix">
      <%= f.label :first_name, 'First name*' %>
      <div class="input">
        <%= f.text_field :first_name, :data => {:error => 'First name'} %>
        <span id="first_name_error"></span>
      </div>
    </div>
    <div class="clearfix">
      <%= f.label :last_name, 'Last name*' %>
      <div class="input">
        <%= f.text_field :last_name, :data => {:error => 'Last name'} %>
        <span id="last_name_error"></span>
      </div>
    </div>
    <div class="clearfix">
      <%= f.label :email, 'Email*' %>
      <div class="input">
        <%= f.text_field :email, :data => {:error => 'Email'} %>
        <span id="email_error"></span>
      </div>
    </div>
  <%= f.submit "Submit your Order", class: 'btn btn-primary btn-lg', id: 'button', data: { confirm: "Place order?" } %>
<% end %>
users.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$('input').keyup(function(){
  blankValidation.call(this);
});

function blankValidation(){
  var error_name = $(this).data('error');
  console.log(error_name);
  var value = $(this).val();
  console.log(value);
  if(error_name !== undefined){
    var error_id = ('#' + error_name.toLowerCase().replace(' ', '_') + ('_error'));
    var error_message = $(error_id);
    if(value.length === 0) {
      error_message.show().text(error_name + " needed.").addClass('error_class');
      return false;
    }
    else {
      error_message.hide();
      return true;
    }
  }
}

We can dynamically call the data attribute for each element. For example, the error_name value the keyup event(m) will console.log (=> First name, m). The call method allows us to refactor all of our keyup event listeners into one method. The call method as defined by the Mozilla guide "calls a function with a given this value and arguments provided individually."

h/t Dan Porter

Reference

Testing Your Way to Success

| Comments

I have been immersed in production codebases for my Fohr Card and Fractured Atlas projects. At first, it feel initimidating trying to figure out all of the models and related associations. I have found that a great way to wrap your head around the code base is to create a new branch and test the code.

A good basic set-up is to start unit testing the models. In order to do this depends on if your codebase is using a relational database or something like Mongoid.

Relational Databases

Gemfile
1
2
3
4
5
6
7
8
9
10
11
 group :development do
    gem 'guard-rspec', require: false
  end

  group :test do
     gem 'rspec-rails'
     gem 'factory_girl_rails'
     gem 'faker'
     gem 'shoulda-matchers'
     gem 'terminal-notifier-guard'
  end
  • Guard RSpec waits for you to save your files and automatically runs your tests, thereby reducing the time needed to run tests.
  • I like the RSpec syntax over Unit Test and Mini Test.
  • Factory Girl Rails creates objects for your tests. This gem deserves its own blog post.
  • The Faker Gem is used in conjunction with Factory Girl Rails to create fake data.
  • I like to use Shoulda Matchers to test validaitons and associations in the code. This gem and firing up Rails Console to play with the objects in my testing is the crux to learning a new codebase.
  • Some people find Terminal Notifier annoying, but it helps me know if my tests pass when I have Sublime maximized on my 11 inch MacBook Air screen.

Mongoid

Gemfile
1
2
3
4
5
6
7
8
9
10
11
 group :development do
    gem 'guard-rspec', require: false
  end

  group :test do
    gem 'fabrication'
    gem 'faker'
    gem 'rspec-rails'
    gem 'mongoid-rspec'
    gem 'terminal-notifier-guard'
  end

The gems for Mongoid testing are similar to those used in testing with a relational database.

  • The Fabrication gem is similar to building objects with Factory Girl, except the documentation website rocks.
  • The Mongoid RSpec gem is similar to Shoulda-Matchers

Gems

Guard RSpec
RSpec Rails
Factory Girl Rails
Faker
Shoulda Matchers
Terminal Notifier Guard
Fabrication
Mongoid RSpec

Other Resources

I found this book invaluable in learning best practices in testing: Everday RSpec
h/t Victoria Friedman

Changing Your Password From Scratch

| Comments

So say you are using devise and have none of the has_secure_password medthod available to you. One should learn the bcrypt gem... and needs to abstract some methods in order to parse an encrypted password. Cool, Bcrypt can do that, as located here. Here is my modified code in order to confirm if a new password in order to apply a boolean value to an inputed password.

edit.html.haml lang: ruby
1
2
3
4
5
6
7
8
9
10
11
 %li
      = f.label :current_password
      = f.password_field :current_password
      # => 'password'
    %li
      = f.label :new_password, 'New Password'
      = f.password_field :new_password
      # => 'new_password'

  .buttons
    %button Save
user.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

  def authenticate(unencrypted_password)
    if BCrypt::Password.new(encrypted_password) == unencrypted_password && self
      bcrypt = ::BCrypt::Password.new(encrypted_password)
      # creates a bcrypt variable if the encrypted passwors result is true
      # => "$2a$10$wgOzLhy84peHUD9wr9UkgOKRpwfls/0h48NYVvKIOdUdbz3XOEpSK" 
      password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
      # then salts the new password
      # => "$2a$10$VUNoD3xdAp7ytTIsTyH5feY.DNUKA4efIdkcI6ViBQ532o8lyNV/e" 
      user = nil unless reset_secure_compare(password, encrypted_password)
      return true
    else BCrypt::Password.new(encrypted_password) != unencrypted_password && self
      return false
    end
  end

You might be wondering what the reset_secure_password method is doing. Well, it is pulled from the Devise docs and is preventing timing attacks, when an attacker attempts to compromise an encryption by analyzing the time taken in order to execute the password and salting algorithms.

Cool, now I can pass my current_password attribute to make sure it is true. I need to make a custom Active Record Validations.

user.rb
1
2
3
4
5
 def correct_password_update_validator
    if self.authenticate(current_password) == true and current_password.present? and new_password.present?
      self.encrypted_password = ::BCrypt::Password.create(new_password)
    end
   end

If this validates, encrypted_password on the database returns true. Now I need validations for events with blank fields (I want nothing to happen), and also, if current_password is blank and new_password and present, visa versa.

user.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 validate :incorrect_password_update_validator, on: :update
  validate :correct_password_update_validator, on: :update
  validate :current_password_present, on: :update
  validate :new_password_present, on: :update
  validate :current_password_true_present, on: :update

  private

  def current_password_true_present
    if self.authenticate(current_password) == true and new_password.blank? and current_password.present?
      errors.add(:new_password, " needs to be filled out.")
    end
  end

  def current_password_present
    if self.authenticate(current_password) == false and new_password.present? and current_password.blank?
      errors.add(:current_password, " needs to be filled out.")
    end
  end

  def new_password_present
    if self.authenticate(current_password) == false and new_password.blank? and current_password.present?
      errors.add(:new_password, " needs to be filled out.")
    end
  end

  def incorrect_password_update_validator
    if self.authenticate(current_password) == false and current_password.present? and new_password.present?
      errors.add(:current_password, " does not match.")
    end
  end

  def reset_secure_compare(a, b)
    return false if a.blank? || b.blank? || a.bytesize != b.bytesize
    l = a.unpack "C#{a.bytesize}"

    res = 0
    b.each_byte { |byte| res |= byte ^ l.shift }
    res == 0
  end

Now, all use cases of the user improperly editing the form result in false and a validation error occurs.

Grep and Scan Methods With Regular Expressions in Ruby

| Comments

I am creating an app to provide food cart locations in Manhattan. Here is the code. Food carts generally post their locations on Twitter; in order to create latitude and longitude coordinates, I needed to parse tweets. This is where scan and grep play their role, to match elements in a tweet string. Let's say this is our tweet: "53rd and park. Ready by 11!" This string is database column in my locations model.

Code for scan method.

1
2
3
4
5
 tweet = "53rd and park. Ready by 11!"
  tweet.scan(/53/)
  # => ["53"] 
  tweet.scan(/Park/i)
  # => ["park"]

The scan method takes a string as an input. Also, the i is used in the regular expression in order to make it case insensitive.

1
2
 tweet.scan(/Park/)
  #  => [] 

Code for grep method.

1
2
3
4
5
6
7
 tweet = "53rd and park. Ready by 11!"
  tweet_array = tweet.split
  # => ["53rd", "and", "park.", "Ready", "by", "11!"] 
  tweet_array.grep(/53/)
  # => ["53rd"]
  tweet_array.grep(/Park/i)
  # => ["park."]

The grep method takes an array as an input, so use the string split method to turn it into an array seperated by commas. Also, the regular expression matches the entire string. The grep method seems to be more suited as an alternative for the select and map methods. This blog post goes into further detail explaining more cases to use the grep method over more familiar methods.

Hiding Multiple Checkboxes With JQuery

| Comments

I have been developing a quiz app for practice with a more complex schema interface. I wanted to dive deeper into CoffeScript and found the opportunity while trying to figure out how a student can add an answer to a given quiz. If a checkbox for a given answer is checked, I wanted the remaining checkboxes to disappear. Also, if the student checked the incorrect box, the browser should render all checkboxes again. Here is my code.

questions.js.coffee
1
2
3
4
5
6
7
8
9
   $('form').on 'click', '.checker', (event) ->
      boxes = $(":checkbox:checked")
      nboxes = $(":checkbox:not(:checked)")
      if boxes.length == 1
          $('.checker_label').hide()
          nboxes.hide()
      if boxes.length == 0
          $('.checker_label').show()
          nboxes.show()

... and the view

_form.html.haml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Quiz:
= @quiz.name

= form_for @question do |f|
  = f.hidden_field :quiz_id, value: @quiz.id
  = f.label "What is your question?"
  = f.text_field :content
  %br
  %fieldset
      = f.fields_for :answers do |builder|
          = builder.label :content, "Answer"
          = builder.text_field :content
          = builder.label "Correct answer?", class:'checker_label'
          = builder.check_box :is_correct, class: 'checker'
      %br
  = link_to_add_fields "Add an answer choice", f, :answers
  %br
  = f.submit