Andrey Morozov

TILSeptember 18, 2019by Andrey Morozov

Strip Whitespace from Heredocs in Ruby/Rails

UPDATE!

Simple way - it's use:


class Template

  def self.base

    <<~TEXT

      Lorem Ipsum is simply dummy

      Lorem Ipsum is simply dummy

    TEXT

  end

end



> Template.base

=> "Lorem Ipsum is simply dummy\nLorem Ipsum is simply dummy\n"

I forgot about <<~, and that's why I got this TIL bike.


You use heredoc in Ruby/Rails app?

Then you're familiar with the problem..


class Template

  def self.base

    <<-TEXT

      Lorem Ipsum is simply dummy

      Lorem Ipsum is simply dummy

      Lorem Ipsum is simply dummy

    TEXT

  end

end



> Template.base

=> "      Lorem Ipsum is simply dummy\n      Lorem Ipsum is simply dummy\n      Lorem Ipsum is simply dummy\n"

hmm...

I don't want to have so many gaps in the text.

Maybe use them:


class Template

  def self.base

    <<-TEXT

Lorem Ipsum is simply dummy

Lorem Ipsum is simply dummy

    TEXT

  end

end



> Template.base

=> "Lorem Ipsum is simply dummy\nLorem Ipsum is simply dummy\n"

It's good, but the code looks like 💩.

This problem can be solved by using activesupport #strip_heredoc:


class Template

  def self.base

    <<-TEXT.strip_heredoc

      Lorem Ipsum is simply dummy

      Lorem Ipsum is simply dummy

    TEXT

  end

end



> Template.base

=> "Lorem Ipsum is simply dummy\nLorem Ipsum is simply dummy\n"

If you don't have active_support, use refine String with #strip_heredoc which will give similar result:


module Utils 

  refine String do 

    def strip_heredoc

      gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)

    end

  end

end



class Template

  using Utils

  def self.base

    <<-TEXT.strip_heredoc

      Lorem Ipsum is simply dummy

      Lorem Ipsum is simply dummy

    TEXT

  end

end



> Template.base 

=> "Lorem Ipsum is simply dummy\nLorem Ipsum is simply dummy\n"

TILSeptember 16, 2019by Andrey Morozov

Simple way to get all values from hash

In the ruby from the box, we can't find all the hash values if it's nested.

I suggest an easy way to find all the values using recursion.

Example hash:


hash = {

  a: 2,

  b: { c: 3, d: 4, e: {f: 5}}

}


> hash.values

=> [2, {:c=>3, :d=>4, :e=>{:f=>5}}]

That's not an option, we need all the values.


def deep_values(array = [], object:)

  object.each do |_key, value|

    if value.is_a?(Hash)

      deep_values(array, object: value)

    else

      array << value

    end

  end

  array

end



> deep_values(object: hash)

=> [2, 3, 4, 5]

If you run the benchmark with this data, we get the following data:


>  puts Benchmark.measure { 100_000.times { hash.values } }

=> 0.028920   0.002643   0.031563 (  0.032759)



>  puts Benchmark.measure { 100_000.times { deep_values(object: hash ) } }

=> 0.140439   0.003318   0.143757 (  0.146637)

TILSeptember 03, 2019by Andrey Morozov

Git switch command

A switch command has been added in the new version of git

Let's look at examples:


# switched to <branch>

git switch <branch>



# creates a new <branch>

git switch -c <branch>



# switched to commit 

git switch -d <commit> 



# creates and switches to branch from remote. 

# need to use if branch exists in multiple remotes 

git switch -c <branch> --track <remote>/<branch> 



# switch to a branch even if the index or working tree is different from HEAD

# this is used to throw away local changes

git switch --discard-changes <branch>



# alias for  --discard-changes

git switch -f <branch> 



# switch back to the previous branch before we switched

git switch - 

Command available on version Git 2.23.0 or higher

TILJanuary 28, 2019by Andrey Morozov

Use gem Recorder for db log 💪

Gem Recorder tracks changes of your Rails models

For start use this library in Rails 5.2 you need add gem to the Gemfile:


gem 'recorder', github: 'jetrockets/recorder', branch: 'rails_5_2'

Next:


> bundle install

> rails g recorder:install

> rails db:migrate

And final step -- add to model:


include ::Recorder::Observer

recorder async: false

And it's all 🎉

For an example - logs can be issued in the representer:


Recorder::Revision.where(item: object).order(id: :DESC).limit(10).map do |revision|

  {

    revision_id: revision.id,

    userId: revision.user_id,

    userEmail: revision.user&.email,

    change: changes_type(revision)

   }

end 



def changes_type(revision)

  if revision.data['changes'].include?('drive_file_id') && revision.data['changes'].size > 4 && revision.data['changes']['drive_file_id'].present?

    'Object updated & Document generated'

  elsif revision.data['changes'].include?('drive_file_id') && revision.data['changes'].size == 4

    'Document generated'

  elsif revision.data['changes'].include?('number') && revision.data['changes']['number'].nil?

    'Object created'

  else

    'Object updated'

  end

end

But of course this is an abstract example with my data 😏


https://github.com/jetrockets/recorder

TILJanuary 26, 2019by Andrey Morozov

Command for create zip archive without gem's 📁


class CreateZipCommand

  def call(files)

    # Create temp directory for files 

    tmp_dir = Dir.mktmpdir

    tmp_zip_path = File.join(tmp_dir, "files.zip")



    # Move files to the temporary folder you created above

    files.map do |file|

      download_file(file, tmp_dir)

    end



    # Go to the folder and archive the entire contents

    `cd #{tmp_dir} && zip #{tmp_zip_path} ./*`



    # Return zip path

    tmp_zip_path

  end

end



> CreateZipCommand.new.call(files)

=> "/var/folders/bk/0c864z710654sx555jpdpx9c0000gn/T/d20190126-7447-d27fpl/files.zip")



Most gems for working with archives eat a lot of memory when working with large files. This solution does not have these problems.

Make sure that the zip utility is installed on your computer - it don't work without it

TILJanuary 23, 2019by Andrey Morozov

Webhook integration in development with Ngrok 🚀

All begin when I’m using the Pipedrive (is a sales management tool designed to help small sales teams manage intricate or lengthy sales processes) webhook.

The solution was easy I just create an ngrok tunnel


> ngrok http 3000 



Session Status                online

Account                       Andrey (Plan: Free)

Version                       2.2.8

Region                        United States (us)

Web Interface                 http://127.0.0.1:4040

Forwarding                    http://b1256cb6.ngrok.io -> localhost:3000

Forwarding                    https://b1256cb6.ngrok.io -> localhost:3000

and then sent the webhook to the generated address and it works. In local development I can user webhook from another api! It's work 🚀

To use it you need to do 4 steps:

  1. Register on ngrok

  2. Download ngrok from site

  3. Connect your account

  4. Run it 🚀


ps

In addition, this service has a ngrok-tunel gem that allows you to fully integrate it with your application. But that's another story 💎