Logo

TODAY I LEARNED

How do you guys set up naked domains in Heroku apps?

Let's say:

I have mydomain.mx and I want to allow anybody to type in the browser

www.mydomain.mx
# or
mydomain.mx
# or
http://mydomain.mx
# or
http://www.mydomain.mx

And to resolve/redirect to the secure version of it -> https://mydomain.mx (non www)

It is basically done, following this approach:

  1. You need to go to the settings section in Heroku.com and enabling the SSL option(only available in hobby and paid plans)
  2. Add your domain with two variations inside the settings section within heroku.com

  3. Create those two CNAMEs entries in your DNS providers (I'm using cloudfare.com for free)

  4. Create a redirect rule in your application(this depend on the technology and language you are using), in my case, as I'm using Rails, so it was a matter of adding this to the top of the config/routes.rb file:

  match '(*any)',
    to: redirect(subdomain: ''),
    via: :all,
    constraints: { subdomain: 'www' }

There you go! you are ready to go, here is a live example (Site in construction as of November 26th, 2021)

www.valoralo.mx
http://valoralo.mx
http://www.valoralo.mx
valoralo.mx

All of them will resolve to the same domain: https://valoralo.mx

Learned by heriberto-perez on Nov 26, 2021

Spaceship Operator <=>

The spaceship operator compares two objects (from left to right), returning either -1, 0, or 1.

Explanation

a <=> b

return -1 if a < b
return 0 if a == b
return 1 if a > b
4 <=> 7 # -1
7 <=> 7 # 0
7 <=> 4 # 1

Example one

As you know, in ruby (as in any language) we can get a result in different ways, we could use just the sort method, of course, but I just wanted to put this in another way:

languages = ['ruby', 'go', 'javascript', 'phyton', 'rust', 'elixir']

languages.sort{|first, second| first <=> second } # ["elixir", "go", "javascript", "phyton", "ruby", "rust"]

languages.sort{|first, second| second <=> first } # ["rust", "ruby", "phyton", "javascript", "go", "elixir"]

Example two

Suppose that we have the next array with the numbers 1 to 10, and we will like to separate them into different groups: 1. One group for the numbers that are less than 5 2. Another group with the number 5 3. The last group with the numbers that are greater than 5

We could get this result by iterating the array and then by putting a couple of if statements in order to group these 3 categories, but with the spaceship operation we could get this result in an easier way:

numbers = Array(1..10)
target = 5

numbers.group_by{ |number| number <=> target } # {-1=>[1, 2, 3, 4], 0=>[5], 1=>[6, 7, 8, 9, 10]}

Learned by samantha-bello on Nov 19, 2021

973983 adforcodereview v3 0211021 c02 021121

Sort an array of objects by a property value

Imagine that we have the next object:

const names = [
  { name: 'Sam', lastName: 'Belmor'},
  { name: 'Yasser', lastName: 'Velasco' },
  { name: 'Ayrton', lastName: 'Morales' }
]

If we wanna sort those values alpabethically by name we could do this:

names.sort((a, b) => (a.name > b.name) ? 1 : -1)

We'll have this result:

[
  { name: 'Ayrton', lastName: 'Morales' },
  { name: 'Sam', lastName: 'Belmor' },
  { name: 'Yasser', lastName: 'Velasco' }
]

If return 1, the function communicates to sort() that the object b takes precedence in sorting over the object a. Returning -1 would do the opposite.

Learned by samantha-bello on Nov 16, 2021

Use 'super' and add custom arguments to a specific class

Sometimes we want to create a parent class that will be shared for children classes, nevertheless, in some of the children classes we need additional arguments that will be only specific for that class and we don't need them in the parent class, to avoid adding additional arguments that won't be relevant to the parent class, we can do the next:

class ParentClass
  attr_reader :user

  def initialize(user)
    @user = user
  end
end
class ChildOne < ParentClass
  attr_reader :token

  def initialize(user, token)
    super(user)
    @token = token
  end
end

This way the new variable token will be available only for the ChildOne class.

Learned by samantha-bello on Nov 12, 2021

973983 adforcodereview v3 0211021 c02 021121

Constant resolution operator `::`

Also, known as scope resolution operator.

When we work with namespace it's very common to override some objects, etc that we already have. This could cause us headaches when we try to access a specific object and that object has the same name as our namespace. To have a clearer idea, let's review the next example, imagine that we have the next nested modules:

module FHIR
  module Services
    module Appointment
      def appointment
        @appointment ||= Appointment.find(id)
      end
    end
  end
end

If you do Appointment.find(id) you will get an error similar to this: NoMethodError: undefined method 'find' for FHIR::Services::Appointment:Module.

That ^ is because the Appointment is doing reference to the namespace FHIR::Services::Appointment (local scope) instead of the Appointment model (global scope).

The constant resolution operator will help us to resolve this. If you put:

::Appointment.find(id)

This will work because is referencing the global namespace which is the Appointment model this way you can access directly to the model instead of the current namespace.

Learned by samantha-bello on Nov 5, 2021

'fixup' and 'rebase' for neat commits

Description

Sometimes we are working on a branch and we want a specific change in a specific commit that is not the last one, we could use fixup to have our commits neat and to avoid doing a disaster with them.

Example

Imagine that we have a commit story like this:

commit 30e9b16e098315e459f46313c099317ab74decbd
Author: Sam Belmor <sambelmor@gmail.com>
Date:  Tue Sep 28 18:57:32 2021 -0500

  Add the MVC architecture

commit e13f8600584a8b304c25d08bbaa13d1999f51569
Author: Sam Belmor <sambelmor@gmail.com>
Date:   Tue Sep 28 18:51:06 2021 -0500

  Add koa/node setup

commit b4b7ee003d554fa7eaa967bcf236c9a02c5a7249
Author: Yasser Batas <yassk8@gmail.com>
Date:   Thu Jul 15 07:11:39 2021 -0500

  Initial commit

If we do some changes related to the koa/node setup and we want those changes in the second commit e13f8600584a8b304c25d08bbaa13d1999f51569, to avoid doing another commit we could do the following:

1. Add your changes

git add .

2. Copy the commit key where you want your changes

For this example we want the changes in the commit Add koa/node setup with the key e13f8600584a8b304c25d08bbaa13d1999f51569.

git commit --fixup e13f8600584a8b304c25d08bbaa13d1999f51569

3. At this point your changes were added, if you put:

git log

You will see something like this:

commit 3ef0a9c5a3a67b5dff7a7f6374921babf7a40c12 (HEAD -> feature/#2-knex-setup)
Author: Sam Belmor <sambelmor@gmail.com>
Date:   Thu Oct 21 11:50:35 2021 -0500

  fixup! Add koa/node setup

commit 30e9b16e098315e459f46313c099317ab74decbd
Author: Sam Belmor <sambelmor@gmail.com>
Date:  Tue Sep 28 18:57:32 2021 -0500

  Add the MVC architecture

commit e13f8600584a8b304c25d08bbaa13d1999f51569
Author: Sam Belmor <sambelmor@gmail.com>
Date:   Tue Sep 28 18:51:06 2021 -0500

  Add koa/node setup

commit b4b7ee003d554fa7eaa967bcf236c9a02c5a7249
Author: Yasser Batas <yassk8@gmail.com>
Date:   Thu Jul 15 07:11:39 2021 -0500

  Initial commit

As you can see a new commit was added, with the difference that you'll see the fixup! word before the commit's description

fixup! Add koa/node setup

At this point, you should check if this is the commit where you want your changes. If this is correct go-ahead to the next point if you made a mistake you could do:

git reset HEAD~

And start again. Be sure to copy the correct commit's key.

4. Use squash to join your commits

Now you're ready to squash your new changes with your old commit. 1. First, you need to copy the previous commit's key from the one that I want to do the squash. For this example the key that I need is this key b4b7ee003d554fa7eaa967bcf236c9a02c5a7249 from this commit Initial commit 2. So you should put the following:

git rebase -i --autosquash b4b7ee003d554fa7eaa967bcf236c9a02c5a7249

5. Confirm your changes

When you do the previous command a text editor will open (nano, vim, etc), and you will see something like this:

pick e13f860 Add koa/node setup
fixup 3ef0a9c fixup! Add koa/node setup
pick 30e9b16 Add the MVC architecture

When you close that window, your changes will be saved and now you'll have the new changes in the corresponding commit.

Learned by samantha-bello on Oct 22, 2021

.forEach .map() loop JavaScript

For Each .forEach iterates the elements of an array but does not return a value.

const a = [1, 2, 3];
const newArray = a.forEach((num, index) => {
  //do something 
});

// newArray = undefined

Map .map iterates the elements of an array but return a new array.

const a = [1, 2, 3];
const newArray = a.map(num => {
  return num * 2;
});

// newArray = [2, 4, 6]

Learned by leyaim-jimenez on Oct 18, 2021

973983 adforcodereview v3 0211021 c02 021121

Separate health check endpoint using puma

Puma offers a way to query its internal stats by enabling a controll app in a separate port, this can be useful when we need to know if the app is alive, this is different than normal health check endpoints because it does not get processed by rails at all.

To enable this functionality, all you need to do is to add this line in your puma.rb file:

activate_control_app 'tcp://0.0.0.0:9293', { no_token: true }

It will start a second web server in the port 9293 that can be queried by monitoring tools or even balancer healthcheck.

ecruz@Edwins-MBP % curl 'http://127.0.0.1:9293/stats'
{"started_at":"2021-10-15T21:39:55Z","workers":2,"phase":0,"booted_workers":2,"old_workers":0,"worker_status":[{"started_at":"2021-10-15T21:39:55Z","pid":44969,"index":0,"phase":0,"booted":true,"last_checkin":"2021-10-15T21:40:05Z","last_status":{"backlog":0,"running":5,"pool_capacity":5,"max_threads":5,"requests_count":0}},{"started_at":"2021-10-15T21:39:55Z","pid":44970,"index":1,"phase":0,"booted":true,"last_checkin":"2021-10-15T21:40:05Z","last_status":{"backlog":0,"running":5,"pool_capacity":5,"max_threads":5,"requests_count":0}}]}%
ecruz@Edwins-MBP %

Check the documentation for more options/usages

Learned by Edwin Cruz on Oct 15, 2021

Numberic separators JavaScript

Numberic separators is a new JavaScript feature that allows you to use underscores as separators to help to improve readability using a visual separation between groups of digits.

// A billion
const amount = 1_000_000_000;

// Hundreds of millions     
const amount = 1_475_938.38;

// 6234500 cents (62345 dollars)
const amount = 62345_00;

// 1,734,500
const amount = 1_734_500; 

// 20^30000
const amount = 2e30_000;

Learned by leyaim-jimenez on Oct 11, 2021

973983 adforcodereview v3 0211021 c02 021121

Javascript event loop

The event loop is the secret behind JavaScript's asynchronous programming. JS executes all operations on a single thread, but using a few smart data structures, it gives us the illusion of multi-threading but first we have to understand the Call Stack.

Call Stack

The call stack works based on the LIFO principle(last in first out) When you execute a script, the JavaScript engine creates a Global Execution Context and pushes it on top of the call stack.

function multiply(a, b) {
    return a * b
}

function squere(n) {
    return multiply(n, n)
}

function printSquere(n) {
    var result = squere(n)
    console.log(result)
}

printSquere(4)

**Stack**
4- multiply
3- squere
2- printSquere
1- main

Result: 16

Call Stack with async callbacks (Even loop)

The event loop facilitates this process; it constantly checks whether or not the call stack is empty. If it is empty, new functions are added from the event queue. If it is not, then the current function call is processed.

An example of this is the setTimeout method. When a setTimeout operation is processed in the stack, it is sent to the corresponding API which waits till the specified time to send this operation back in for processing.

console.log('hi')

setTimeout(()=> {
  console.log('there')
},5000)

console.log('bye')

**Stack**
3- there
2- bye
1- hi

**webapis**
setTimeout callback(cb)

**taskqueue**
callback(cb)

**evenloop**
move cb to stack

In the example the setTimeout Callback enters the webapi stack executes and then goes to the task queue and waits for the stack to become empty and the event loop moves the callback to the stack.

Learned by leyaim-jimenez on Oct 1, 2021

module_function

What it does?

  • module_function allows exposing instance’s methods so they can be called as they would be class methods.
module User
  def name
    'Hello Sam'
  end
end

If you try to do this:

user = User.new
user.name

You're gonna receive an error because modules do not respond to the new method.

How can we use it?

You can use this useful method module_function:

module User
  module_function

  def name
    'Hello Sam'
  end
end

And call the name method like User.name

  1. Use module_function to use all the methods inside a module as class methods or
  2. Use module_function :name to only apply it in a specific method

A second option to do it

Another option to do so is using extend self instead:

module User
  extend self

  def name
    'Hello Sam'
  end
end

Learned by samantha-bello on Sep 29, 2021

973983 adforcodereview v3 0211021 c02 021121

Truthy and Falsy Values

If JavaScript's built-in type coercion makes it true, thats mean that the values is a truthy.

  true
  {}
  []
  42
  "0"
  "false"
  new Date()
  -42
  12n
  3.14
  Infinity
  -Infinity

and in Javascript a falsy value is a value that is considered false

  false
  0
  0n: 0 as a BigInt
  '': Empty string
  null
  undefined
  NaN

Learned by leyaim-jimenez on Sep 28, 2021

Underscores are not allowed as part of domain names

According to rfc1035, underscores (_) are not allowed as part of domain names.

The labels must follow the rules for ARPANET host names. They must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen (-). There are also some restrictions on the length. Labels must be 63 characters or less.

This means domain names like my_domain.com or sub_domain.main-domain.com are invalid.

Special thanks to @jclopezdev for finding this out.

Learned by kevin-perez on Sep 28, 2021

973983 adforcodereview v3 0211021 c02 021121

JavaScript null vs undefined

In JavaScript null and undefined are rather strange values, both serve a very similar purpose, which is to indicate the absence of a value.

Null

Null is used to assign a reference to an object that you will no longer need or, directly, you want to have the variable declared but initialize it with a value that you still do not know what it will be exactly. In all these cases the best thing to do is to assign a null value.

  var miVariable = null;
  console.log(miVariable);

//log null

undefined

For undefined means that the variable is declared but its value has not yet been defined.

  var miVariable
  console.log(miVariable);

//log null

Both values are values of type false, so if you do a non-strict comparison you will get true undefined, which means that the variable is declared but its value has not yet been defined.

if (null == undefined) {
  return true
 }
//log true

and if you do a strict comparison, because they are not really the same, it returns a false:

if (null === undefined) {
   return true
 }
return false
//log false

Learned by leyaim-jimenez on Sep 21, 2021

Javascript Hoisting

This means that variable and function declarations are physically moved to the beginning of the code and are allocated in memory during the compilation phase.

function welcomeTo(name) {
  console.log("Welcome to " + name);
}

welcomeTo("Magmalabs");
//returns welcome to magmalabs

As you can see hoisting allows you to use a function before declaring it in the code.

welcomeTo("Magmalabs");

function welcomeTo(name) {
  console.log("Welcome to " + name);
}
//returns welcome to magmalabs

And also allows you to use a function after declaring it in the code.

For variables, hoisting only applies to the declaration, not to their assignment. example:

We declare the variable name but we got an undefined

console.log(name); 
var name = magmalabs;
//return undefined

That’s because JavaScript only hoist the declaration

var name;

console.log(name); 
name = magmalabs;
//return undefined

To avoid these errors, it is very important to keep in mind that hoisting only applies to the declaration.

Learned by leyaim-jimenez on Sep 17, 2021

973983 adforcodereview v3 0211021 c02 021121

Profiles in docker compose, specify default services

It is common to have multiple services listed in the docker-compose file, sometimes with dependencies, but also, a normal workflow sometimes is to just start everything, like:

docker-compose -f docker-compose.yml -d

And it will start all servies listed with their dependencies, but, what happens if you need to add another service and you do not need it to start along with the rest? The answer is: profiles:

services:
  db:
    image: pg
  cache:
    image: redis
  rails:
    depends_on:
      - db
      - cache
    command: puma
  sidekiq:
    profiles: [ 'jobs' ]
    depends_on:
      - db
      - cache
    command: sidekiq

So, in this case, whenever you do docker-compose up -d it will start only rails with its dependencies: db and cache, it wont start sidekiq by default, but if you really want to start sidekiq, then you need to explicitly type it: docker-compose up sidekiq -d.

Learned by Edwin Cruz on Sep 15, 2021

Eager load rails associations with nested scopes

It is common to apply some extra scopes when fetching AR relationships, for examples, if we have countries and states, we might want all the countries starting with the letter A and all their states that starts with the letter B, this will automatically create a n+1 query problem since it nees to iterate over each country and fetch all states, but, Rails provides a way to eager load these associations easily:

states_scope = State.where("name ilike 'b%'")
countries = Country.where("name ilike 'a%'")
# This is the magic
ActiveRecord::Associations::Preloader.new.preload(countries, :states, states_scope)

# Now you can invoke coutries.each(:states) and it wont cause queries N+1
countries.map {|country| { country.id => country.states.size }

Normally, you would have to define another relationship in order to eager load the association, but it is not needed using this approach:

class Country < AR::Base
  has_many :states
  has_many :states_starting_with_b, -> { where("name ilike 'b%'") }, foreign_key: :state_id, class_name: "State"
end

# Then
Country.includes(:states_starting_with_b).where("name ilike 'a%'")

But this approach does not scale, it requires to define tons of relationships

Learned by Edwin Cruz on Sep 9, 2021

973983 adforcodereview v3 0211021 c02 021121

Docker compose services with health checks

If you need to add extra checks for services to be up and running before starting another one, you can use healtcheck property:

services:
  pg:
    image: pg/pg-12
    ports:
      - 5432:5432
    healtcheck:
      test: [ "CMD-SHELL", "pg_isready -U postgres" ]
      interval: 5s
      timeout: 5s
      retries: 5
  redis:
    image: redis:5.0.4-alpine
    ports:
      - 6380:6379
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      interval: 5s
      timeout: 5s
      retries: 5
  app:
    image: railsapp
    depends_on:
      pg:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports: ['3000:3000']
    command: |
      bash -c "bundle exec rails s"

Learned by Edwin Cruz on Sep 8, 2021

Typeprof Ruby Interpreter in Ruby 3.0+

TypeProf is a Ruby interpreter that abstractly executes Ruby programs at the type level. It executes a given program and observes what types are passed to and returned from methods and what types are assigned to instance variables. All values are, in principle, abstracted to the class to which the object belongs, not the object itself.

Example: 1

 $ typeprof user.rb
# TypeProf 0.12.0

# Classes
class User
  attr_accessor skip_add_role: untyped
  def self.from_omniauth: (?Hash[bot, bot] auth) -> User

  private
  def assign_default_role: -> nil
end

Example 2:

 $ typeprof skill.rb
# TypeProf 0.12.0

# Classes
class Skill
  private
  def acceptable_image: -> nil
end

Example 3:

 $ typeprof ability.rb
# TypeProf 0.12.0

# Classes
class Ability
  attr_accessor user: untyped
  def initialize: (untyped user) -> untyped

  private
  def alias_actions: -> untyped
  def register_extension_abilities: -> untyped
end

Learned by Victor Velazquez on Aug 13, 2021

973983 adforcodereview v3 0211021 c02 021121

Rails + Facebook Oauth Locally with SSL

Recently I had the need to test Oauth with Facebook locally and after creating and configuring the App and everything was working wonderfully ...

until it was not.

Facebook now forces SSL so I had to setup it locally by creating a self signed certificate and running my server with it.

  1. Create your certificate, this script create it as localhost.mumoc.crt and localhost.mumoc.key. Mumoc is my username in my working machine.
name=localhost.$(whoami)
openssl req \
  -new \
  -newkey rsa:2048 \
  -sha256 \
  -days 3650 \
  -nodes \
  -x509 \
  -keyout $name.key \
  -out $name.crt \
  -config <(cat <<-EOF
  [req]
  distinguished_name = req_distinguished_name
  x509_extensions = v3_req
  prompt = no
  [req_distinguished_name]
  CN = $name
  [v3_req]
  keyUsage = nonRepudiation, digitalSignature, keyEncipherment
  extendedKeyUsage = serverAuth
  subjectAltName = @alt_names
  [alt_names]
  DNS.1 = $name
  DNS.2 = *.$name
EOF
)

Make sure to at least add digitalSignature and keyEncipherment to KeyUsage or you won't be able to use it in Chrome

  1. Trust the certificate (I moved it to a config/ssl directory inside my app folder)
mv localhost.mumoc.* config/ssl
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain config/ssl/localhost.mumoc.crt
  1. Run server binding the ssl with the key and certificate
rails s -b 'ssl://localhost:3000?key=config/ssl/localhost.mumoc.key&cert=config/ssl/localhost.mumoc.crt'

Learned by carlos-muniz on Jul 29, 2021

973983 adforcodereview v3 0211021 c02 021121

ON DUPLICATE KEY UPDATE

When you're doing an INSERT query, you could be trying to insert a row containing a primary key that already exists in the table. Instead of doing a previous query to see if the key exists or not, you could try ON DUPLICATE KEY UPDATE.

INSERT INTO table (
  field1, 
  field2
) 
VALUES (
  "foo", 
  "bar"
) 
ON DUPLICATE KEY UPDATE 
  field1="foo", 
  field2="bar"

Learned by kevin-perez on Jul 6, 2021

You can forward/reverse ports on Android device using adb

I'm developing an Android app as a side project and today I learned about adb forward and adb reverse. Basically, they allow you to forward or reverse traffic to specific ports between an Android device and your development machine.

Let's say I need my app to fetch something from http://localhost:3000/some-data. When the app is running on the phone localhost refers to the phone itself, and my server is running in my dev machine. So, if I do this:

adb reverse tcp:3000 tcp:3000

Now when the app tries to access localhost:3000 it will actually reach out to my dev machine's 3000 port. Very useful if you're developing the app's backend as well (as I am).

Similarly, if I wanted to access a server inside the phone from my dev machine, I could run:

adb forward tcp:5000 tcp:5000

And now if I run curl http://localhost:5000 in my dev machine it will hit the server running on the phone. Pretty neat!

Learned by kevin-perez on Jun 30, 2021

973983 adforcodereview v3 0211021 c02 021121

How to run a single test from a file using Cypress

I can run all tests from a file with:

yarn run cypress:run -s path/to/file.spec.js

but what about when I want to run only one test case from that file and not all of them?

We could use only()

// path/to/file.spec.js

it.only('just run this test', () => { ... })

it('not run this test', () => { ... })

// we could also use describe.only() but IDK if that is a bug or a feature xD

Run again yarn run cypress:run -s path/to/file.spec.js to see how the it.only() test will run it

Learned by rogelio-alatorre on Jun 25, 2021

TIL about the attention economy

As a UX designer, the product you create will constantly compete for users’ attention. If users are paying attention to one thing, like a notification on their mobile phone, it means they’re ignoring something else, so users have to be selective about how they spend time! This battle over users’ attention is referred to as the attention economy.

The term attention economy originated with psychologist and Nobel Laureate Herbert A. Simon, who believed that there are limits on what humans can think about and do at one time. Many scientists believe that humans aren’t very good multitaskers; technology should help users, not distract them. The more distracted a person is, the less likely they are to complete a task well.

Learned by aldo-mosqueda on Jun 14, 2021

973983 adforcodereview v3 0211021 c02 021121

Set and preserve cookies on and Axios API call

I was using Axios to test an API created in Rails, trying to set up cookies for a User Authentication process. After attempting to get the information back i realize that the cookie was not persistent, due to the lack of one parameter... withCredentials: true So if you want your session to store cookies in the client side and have them available remember to pass it to the call import axios from import axios from 'axios' axios.post(API_SERVER + '/login', { email, password }, { withCredentials: true }) Otherwise the cookie would not be saved.

Learned by fabian-alcala on Jun 10, 2021

The Mehrabian rule

Today I learn the Mehrabian 7-38-55 rule. The rule states that: 7% of meaning is communicated through spoken word 38% through tone of voice, and 55 % through body language.

It was developed by psychology professor Albert Mehrabian at the University of California, Los Angeles.

So... it is always a good idea to keep our cameras on at every meeting ;)

Learned by aldo-mosqueda on May 28, 2021

Other errors when installing Capybara Webkit Gem - M1 Mac Big Sur

Well, it turns out that installing capybara-webkit gem can give you different problems, in my case I had to install

capybara-webkit -v '1.15.1'.

You need to install QT as a dependecy.

The latest versions of QT including 5.6 returns the following message:

QtWebKit is no longer included with Qt 5.6

I followed one of our guides here, however it appears that QT version 5.5 was removed.

cd $( brew --prefix )/Homebrew/Library/Taps/homebrew/homebrew-core
git checkout 9ba3d6ef8891e5c15dbdc9333f857b13711d4e97 Formula/qt@5.5.rb
brew install qt@5.5

curl: (22) The requested URL returned error: 404
Error: Failed to download resource "qt@5.5_bottle_manifest"
Download failed: https://ghcr.io/v2/homebrew/core/qt/5.5/manifests/5.5.1_1

I also tried through binary installer but I got the following error:

Error creating SSL context

I finally succeeded, installing an older version

brew tap cartr/qt4
brew install qt@4
brew install qt-webkit@2.3
gem install capybara-webkit -v '1.15.1'

Building native extensions. This could take a while...
Successfully installed capybara-webkit-1.15.1
1 gem installed

Learned by jennifer-ledezma on May 26, 2021

973983 adforcodereview v3 0211021 c02 021121

while on a Capybara / Cucumber test execution How to save and open the page as snapshot in a browser for inspection

While debugging a cucumber test (within an specific step for an specific scenario) with a binding.pry I wanted to see the html as it is with inputs and outputs of data at the moment (and because I usually run tests with Capybara headless option), I realized the existance of:

save_and_open_page

it Saves a snapshot of the page and open it in a browser for inspection

https://www.rubydoc.info/github/jnicklas/capybara/Capybara%2FSession:save_and_open_page

Note: ^ be sure to have the gem 'launchy' within test env so that it works

Learned by victor-delarocha on May 12, 2021

Fixing the Capybara Webkit Gem installation - QtWebKit is no longer included with Qt 5.6 error on M1 Mac with Big Sur

If you installed any version above 5.6 make sure you uninstall all those versions, for instance:

MacBook-Air:myproject heridev$ brew uninstall qt
Uninstalling /usr/local/Cellar/qt/6.0.3_2... (8,233 files, 158.7MB)
MacBook-Air:myproject heridev$ brew uninstall qt@5
Uninstalling /usr/local/Cellar/qt@5/5.15.2... (10,688 files, 367.9MB)

Then we need to install the 5.5 version (old version):

cd $( brew --prefix )/Homebrew/Library/Taps/homebrew/homebrew-core
git checkout 9ba3d6ef8891e5c15dbdc9333f857b13711d4e97 Formula/qt@5.5.rb
// this will install the qt from shopify/shopify
brew install qt@5.5

And make sure you add the qt PATH in my case:

echo 'export PATH="/usr/local/opt/qt@5.5/bin:$PATH"' >> /Users/heridev/.bash_profile
source ~/.bash_profile

Now, you should be able to install the capybara webkit gem without any problems

Learned by heriberto-perez on May 5, 2021

973983 adforcodereview v3 0211021 c02 021121

User Stories

As a [UX Designer] I want to [embrace Agile] so that [I can make my projects user-centered]

TIL that User Stories were originated as part of the Agile and SCRUM development methodologies. A tool so simple yet so powerful, it is a great design method that enhances collaboration.

Read the entire article: https://bit.ly/3tkB3RE

Learned by aldo-mosqueda on May 5, 2021

Control email deliveries in Rails with a custom Interceptor

You can easily tell Rails to control email delivering with a custom mailer interceptor, all you need to do is to implement the class method delivering_email:

class DeliverOrNotEmailInterceptor
  def self.delivering_email(email)
    mail.perform_deliveries = !email.to.end_with?('special-domain.com')
  end
end

# config/initializer/email_interceptors.rb
ActionMailer::Base.register_interceptor(DeliverOrNotEmailInterceptor)

Learned by Edwin Cruz on May 4, 2021

973983 adforcodereview v3 0211021 c02 021121

Safe access for nested key values in a Hash - dig method

If you are using Ruby 2.3.0 or above

Now instead of doing this:

result.try(:[], 'avatar').try(:[], 'model').try(:[], 'raw_attributes').try(:[], 'signup_state')
# or
result && result['avatar'] && result['avatar']['model'] && result['avatar']['model']['raw_attributes'] && result['avatar']['model']['raw_attributes']['signup_state']

Now you can easily do the same with dig:

result.dig('avatar', 'model', 'raw_attributes', 'signup_state')

Learned by heriberto-perez on Apr 28, 2021

973983 adforcodereview v3 0211021 c02 021121

How to add an image to a gist

1.- Create a gist

2.- Clone your gist:

# make sure to replace `<hash>` with your gist's hash
git clone https://gist.github.com/<hash>.git # with https
git clone git@gist.github.com:<hash>.git     # or with ssh

3.- Open it & move your image

cd <hash>
mv ~/Desktop/image.jpg ~/Projects/gist/image.jpg

4.- Add your image to your gist's repository:

git add image.jpg

5.- Commit the image:

git commit -m "Add image"

6.- Update gist:

git push origin master

image

Learned by Victor Velazquez on Apr 22, 2021

How to understand the SQL behind an ActiveRecord Query

Quick example, to see and understand better how an ActiveRecord query using scopes or methods in the model works at the SQL level and how to run it, all in the same example

Ruby version

Let say you have a database with users and you have some scopes to filter by non-demo, active, and completed providers with a specific Role (CanCanCan behind the scenes) :

User.providers.real.active.completed

Let's look into the SQL version:

If we run this command

irb(main):007:0> User.providers.real.active.completed.to_sql

We would get this:

=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"users_roles\" ON \"users_roles\".\"user_id\" = \"users\".\"id\" INNER JOIN \"roles\" ON \"roles\".\"id\" = \"users_roles\".\"role_id\" WHERE (roles.name = 'Provider') AND \"users\".\"demo_account\" = 'f' AND (\"users\".\"organization_id\" NOT IN (SELECT \"organizations\".\"id\" FROM \"organizations\" WHERE \"organizations\".\"demo_account\" = 't' ORDER BY \"organizations\".\"name\" ASC)) AND \"users\".\"is_active\" = 't' AND \"users\".\"signup_state\" = 'Completed'"

Then we just need to replace the invalid characters such as \ and translate that into a SQL version like this:

SUMMARY_PROVIDERS_REPORT_SQL = <<-SQL
WITH real_providers AS
  ( SELECT users.* FROM users
    INNER JOIN users_roles ON users_roles.user_id = users.id
    INNER JOIN roles ON roles.id = users_roles.role_id
    WHERE (roles.name = 'Provider') AND users.demo_account = 'f'
      AND (users.organization_id NOT IN (
        SELECT organizations.id FROM organizations WHERE organizations.demo_account = 't' ORDER BY organizations.name ASC)
      )
      AND users.is_active = 't' AND users.signup_state = 'Completed')
select real_providers.id, real_providers.name from real_providers
SQL

In order to run it in the Rails console for example:

report_results = ActiveRecord::Base.connection.execute(SUMMARY_PROVIDERS_REPORT_SQL)
report_results.entries

That will give you the id and name of all those valid providers

Learned by heriberto-perez on Apr 21, 2021

973983 adforcodereview v3 0211021 c02 021121

:is() pseudo-class - CSS

When we apply the same style to multiple selectors on CSS we use to do something like this:

.section-header h1,
.section-header span,
.section-header .heading {
  line-height: 1.2;
}
.navigation li,
.navigation p {
  padding: 5px 10px;
}

With :is() we can write our CSS in a shorter way.

.section-header :is(h1, span, .heading) {
  line-height: 1.2;
}
.navigation :is(li, p) {
  padding: 5px 10px;
}

Learned by carlos-pineda on Apr 19, 2021

973983 adforcodereview v3 0211021 c02 021121

Notes on getting my M1 Rails + Foreman environment working

I expect this to evolve quickly and different things seem to be working for different people. In the meantime, hope to avoid a few rabbit holes for others.

  1. rvm worked for ruby 3.0.0 but not 2.6.6 (which is what I needed). cflags workarounds made it so ruby could get installed but gems with native extensions like grpc could not compile correctly. Tried asdf before trying rbenv and it worked, so I stuck with asdf.
  2. Had to prepend every brew installation (including brew itself) with arch -x86_64 brew install ....
  3. After installing asdf, I installed bundler as usual. No arch -x86_64 or anything. Same for bundle install afterwards.
  4. This DriftingRuby episode helped a lot.

I don't think the following were necessary but this is what I did because installing things with brew was getting hairy:

  1. Use Postgres.app to keep PostgreSQL running in the background, deleted it from my Procfile. Naturally, I have to start Postgres manually before I start Foreman.
  2. Downloaded ElasticSearch binaries and put the path in my Procfile. Essentially /Users/jose/dependencies/elasticsearch/elasticsearch-#.#.#/bin/elasticsearch

Learned by jose-farias on Apr 9, 2021

973983 adforcodereview v3 0211021 c02 021121

Using Gem::Dependency class manually to ensure version matching

I needed to add a mechanism to ensure that some actions of a controller were available only for specific versions, and I thought it was super similar of what Gemfile does, so I started to look how to use Gem::Dependency to solve this, and turns out it was super easy:

class Controller
  def feeds_one
    check_for_version_support('>= 1.0', '< 3')

    render json: SomeData.all
  end

  def feeds_two
    check_for_version_support('= 1.0')

    render json: SomeData.all
  end

  def feeds_three
    check_for_version_support('>= 2.1')

    render json: SomeData.all
  end

  private

  def check_for_version_support(*specification)
    checker = Gem::Dependency.new(action_name, specification)

    return if checker.match?(action_name, params[:version])

    raise VersionNotSupported, "Version not upported"
  end
end

Learned by Edwin Cruz on Apr 7, 2021

P.A.R.A. Method

P.A.R.A. stands for Projects — Areas — Resources — Archives

A Project is “a series of tasks linked to a goal, with a deadline.”

An Area of responsibility is “a sphere of activity with a standard to be maintained over time.”

A Resource is “a topic or theme of ongoing interest.”

Archives include “inactive items from the other three categories.”

This Method has captured my attention and has been an exceptional tool for assign our projects, tasks, and resources.

Learned by juan-castillo on Apr 6, 2021

973983 adforcodereview v3 0211021 c02 021121

use bundle open gemname

You can take a peek at a locally installed gem's code very easily in ruby mine.
If you are using another IDE it would require a few extra steps:
First, set BUNDLER_EDITOR in ~/.bashrc or ~/.zshrc (or whatever shell you are using)
export BUNDLER_EDITOR="code"
(code to use VS code)
Then, simply run $ bundle open gemname and voilá! Look at whatever gem you want

Learned by Eduardo Gutiérrez on Apr 6, 2021

973983 adforcodereview v3 0211021 c02 021121

Ruby 2.7 introduced numbered parameters for blocks

Since Ruby 2.7, it is possible to use numbered parameters in blocks additionally to named parameters.

This is an example of a block with named parameters:

my_array.each { |element| element.do_something }

And this is the same line with numbered parameters:

my_array.each { _1.do_something }

This works with multiple parameters too:

# named parameters
my_hash.each_pair { |key, value| puts "#{key}: #{value}" }

# numered parameters
my_hash.each_pair { puts "#{_1}: #{_2}" }

Learned by kevin-perez on Mar 30, 2021

973983 adforcodereview v3 0211021 c02 021121

Browsers' IndexedDB are shared across domain

I was working on a major refactor for a PWA which basically changed the DB schema by reducing the amount of versions, nothing outstanding. BUT, I didn't change the DB name.

I was puzzled why whenever accessing the previous version I had to delete the data to have the app load correctly, then I realized that despite the PWA being located at different URL paths, both versions were using the same IndexedDB because of the same domain policy.

Learned by juan-guajardo on Mar 19, 2021

Using Upsert with Rails

Some DBMS support natively something that behaves like update or insert, Rails recently added the method Upsert that can take advantage of this method.

It is useful to update information that do not need to run validations, meaning, in a super performant way, here's an example:

# We usually do this:
activity = current_user.activity
if activity 
  activity.update(last_seen_at: Time.current)
else
  current_user.activity.create(last_seen_at: Time.current)
end

But if you see, it does not need to run any validation, it just needs to update last_seen_at if exists or create a new one, it performs two queries: one to instanciate the activity object and a second one that performs the real update/insert statement.

That can be replaced with the following code and it will perform just a single query and it will take care to either create the record or update an existing one

Activity.upsert({ last_seen_at: Time.current, user_id: current_user.id}, unique_by: :user_id)

To make this really work, considering you use Postgresql, you have to add a unique index on user_id and modify default value on created_at and updated_at in a migration like this:

query = <<-SQL
  ALTER TABLE #{Activity.table_name}
  ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP,
  ALTER COLUMN updated_at SET DEFAULT CURRENT_TIMESTAMP
SQL
execute(query)

Learned by Edwin Cruz on Mar 19, 2021

973983 adforcodereview v3 0211021 c02 021121

What is your car color?

Did you know that your car color can say a lot about how you want to be perceived by other people? Here is a list of some colors and their own meanings.

White: This color evokes freshness, cleanness, youth, and modernity.

Black: This is the most popular color in luxury vehicles. Black can be described as a sexy, powerful, and mysterious color.

Silver: This color is linked to a sense of innovation and modernity, that is why a lot of high tech products go for silver.

Red: This is a bold color, if your car is red this might mean you want to show an image of power, action, and confidence.

Blue: Blue is often described as the color of stability and safety. If your car is blue this might mean you are a trustworthy person.

Yellow: If you drive a yellow car might mean that you are a happy person or maybe a person who likes to take risks.

Gray: If you have a gray car this could mean you are a person who does not want to stand out, and prefers something a bit more ¨subtle¨ instead.

Learned by omar-miranda on Mar 19, 2021

Better usage of Rails logger

Logging usefull data is a hard task, but there's one specific method that helps to improve the experience of logging actual useful information: tagged. It adds extra tags to the log message making it easy to debug:

Rails.logger.tagged('Super App') do
  Rails.logger.info('Log Message')
end

This will result in somethin like this:

[Super App] Log Message

If you can see, it prepends usefull information, you could add personalized data to trace logs, for example:

class ApplicationController << ActionController::Base
  around_action :add_logger_tags

  def add_logger_tags
    Rails.logger.tagged(logging_tags) do
      yield
    end
  end

  def logging_tags
    [
      "Request Id: #{request.id}",
      "Session Id: #{session.id}",
      current_user && "User id: #{current_user.id}"
    ]
end

And you will have super nice logs to read

Learned by Edwin Cruz on Mar 18, 2021

973983 adforcodereview v3 0211021 c02 021121