D9bf66e0df0902a11c349d06be41c7ae

5 posts by heriberto-perez
@heridev

Ruby partition on arrays

In Ruby, the partition is a very useful method that you can use to filter some items in an array and that you need the ones that satisfy the condition and the ones that do not, and it takes a block of code and returns two arrays: the first contains the elements for which the block of code returns true, and the second contains the elements for which the block returns false.

Let's see an actual example:

def create_fake_emails_array
  emails = []
  10.times do |i|
    emails << { email: "user#{i + 1}@mailinator.com" }
  end

  10.times do |i|
    emails << { email: "user#{i + 1}@something.com" }
  end
  emails
end

my_emails = create_fake_emails_array

class EmailContactsWhitelistCleaner
  attr_reader :email_recipients

  def initialize(email_recipients)
    @email_recipients = email_recipients
  end

  def get_white_list_collection
    valid_recipients, invalid_recipients = partition_emails

    log_black_list_email_recipients(invalid_recipients)
    valid_recipients
  end

  private

  def partition_emails
    email_recipients.partition { |recipient| valid_recipient?(recipient[:email]) }
  end

  def valid_recipient?(email)
    !email.match?('mailinator') || mailinator_white_list.include?(email)
  end

  def log_black_list_email_recipients(invalid_recipients)
    return if invalid_recipients.empty?

    email_list = invalid_recipients.map { |recipient| recipient[:email] }.join(',')
    puts "The following emails are not in the whitelist: #{email_list}"
  end

  def mailinator_white_list
    # ENV.fetch('MAILINATOR_WHITE_LIST', '').split(',')
    'user1@mailinator.com,user2@mailinator.com,user3@mailinator.com'
  end
end

service = EmailContactsWhitelistCleaner.new(my_emails)
puts service.get_white_list_collection

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

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

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')

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