“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey
Senior Software Engineer, UK

Encoding and Extraneous Characters

Came across and interesting problem. We decode a base64 string that is received as a parameter and decode it to work out where to build a new path. The problem here is that the extra characters \xDB\x9D\x00 shouldn’t be there and cause YAML to blow up

2.2.2 :017 > Base64.decode64('LS0tCi0gOnBvbHltb3JwaGljX3BhdGgKLSAhcnVieS9BY3RpdmVSZWNvcmQ6%250AUHJvamVjdAogIGF0dHJpYnV0ZXM6CiAgICBpZDogODAyNQo=%250A')
 => "---\n- :polymorphic_path\n- !ruby/ActiveRecord:\xDB\x9D\x00Project\n  attributes:\n    id: 8025\n"
2.2.2 :023 > YAML.load("---\n- :polymorphic_path\n- !ruby/ActiveRecord:\xDB\x9D\x00Project\n  attributes:\n    id: 8025\n")
Psych::SyntaxError: (<unknown>): control characters are not allowed at line 1 column 1

Somehow control characters are appearing in our Base64 string and we need to strip them. It just doesn’t seem as simple as

2.2.2 :025 > "---\n- :polymorphic_path\n- !ruby/ActiveRecord:\xDB\x9D\x00Project\n  attributes:\n    id: 8025\n".gsub("\xDB\x98\x00",'')
 => "---\n- :polymorphic_path\n- !ruby/ActiveRecord:۝\u0000Project\n  attributes:\n    id: 8025\n"

I found that if you call ord on a single string character you get the ASCII code

2.2.2 :042 > Base64.decode64('LS0tCi0gOnBvbHltb3JwaGljX3BhdGgKLSAhcnVieS9BY3RpdmVSZWNvcmQ6%250AUHJvamVjdAogIGF0dHJpYnV0ZXM6CiAgICBpZDogODAyNQo=%250A').chars[45..47].map(&:ord)
 => [219, 157, 0]

So if I strip those ASCII characters from my string I should be good? Right?

class String
  def without_extended_characters
    chars.select {|s| (1..127).include?(s.ord) }.join
  end
end

and then

2.2.2 :043 > Base64.decode64('LS0tCi0gOnBvbHltb3JwaGljX3BhdGgKLSAhcnVieS9BY3RpdmVSZWNvcmQ6%250AUHJvamVjdAogIGF0dHJpYnV0ZXM6CiAgICBpZDogODAyNQo=%250A').without_extended_characters
 => "---\n- :polymorphic_path\n- !ruby/ActiveRecord:Project\n  attributes:\n    id: 8025\n"

That’s much better and now YAML can decode this successfully.

It is at this stage I notice…. %250A in the Base64 string and at the end of the string. This represents a carriage return, that can happen in parameters easily enough, so I am decoding a carriage return and then stripping it from the string. I should just strip the carriage returns in the first place.

2.2.2 :045 > Base64.decode64('LS0tCi0gOnBvbHltb3JwaGljX3BhdGgKLSAhcnVieS9BY3RpdmVSZWNvcmQ6%250AUHJvamVjdAogIGF0dHJpYnV0ZXM6CiAgICBpZDogODAyNQo=%250A'.gsub('%250A',''))
 => "---\n- :polymorphic_path\n- !ruby/ActiveRecord:Project\n  attributes:\n    id: 8025\n"

Oh well, I learnt about String#ord all the same.

Clam AV and that pesky server


----------- SCAN SUMMARY -----------
Known viruses: 6288879
Engine version: 0.98.7
Scanned directories: 79272
Scanned files: 257567
Infected files: 14
Total errors: 18985
Data scanned: 4639.85 MB
Data read: 5473.88 MB (ratio 0.85:1)
Time: 692.947 sec (11 m 32 s)

/tmp/clamav
/tmp/clamav/maldetect-1.6.tar.gz.001
/tmp/clamav/rfxn.yara.002.001
/tmp/clamav/rfxn.yara.004.001
/tmp/clamav/rfxn.yara.001
/tmp/clamav/rfxn.yara.001.001
/tmp/clamav/rfxn.yara.003.001
/tmp/clamav/x86_64.h.001

Manually restarting Puma

rails@epic-invite-staging:~/apps/epic-invite/staging/current$ bundle exec pumactl -P tmp/pids/puma.pid restart
Command restart sent success

Adding a new role to PostgreSQL

rails@snarf:/var/www/mini-epic/current$ sudo -u postgres createuser --interactive
Enter name of role to add: rails
Shall the new role be a superuser? (y/n) y
rails@snarf:/var/www/mini-epic/current$ RAILS_ENV=staging rake db:create
rails@snarf:/var/www/mini-epic/current$ psql epic_invite_staging < /tmp/mini-epic.pgsql

Instance method defined on class?

class Dave
  def monitor; end
end

Dave.method_defined?(:monitor)
 => true 
Dave.method_defined?(:iareweasel)
 => false

Wow, never seen a C backtrace in Rails before

-- C level backtrace information -------------------------------------------
0   libruby.2.2.0.dylib                 0x0000000103e6e885 rb_vm_bugreport + 149
1   libruby.2.2.0.dylib                 0x0000000103d0dbb4 rb_bug + 468
2   libruby.2.2.0.dylib                 0x0000000103d0deac rb_bug_errno + 92
3   libruby.2.2.0.dylib                 0x0000000103e7cb2c thread_timer + 588
4   libsystem_pthread.dylib             0x00007fffbb4ac9af _pthread_body + 180
5   libsystem_pthread.dylib             0x00007fffbb4ac8fb _pthread_body + 0

-- Other runtime information -----------------------------------------------

* Loaded script: bin/rails

* Loaded features:

    0 enumerator.so
    1 rational.so
    2 complex.so

Enumerable#any?

I always thought Enumerable#any? was equivalent to Enumerable#count > 1

But no…

[nil, nil, nil].any?
#=> false

Google did a thing

I love PacMan but I am not good at it, not even if my own neighbourhood.

rewhere

Interesting problem requiring us to remove the where values on an ActiveRecord::Relation. The original heavy handed method seems to play havoc with chained where calls and the id of the original proxy_association.owner would get used in a later where. Here we can see that our for_me method seems to cause the else_id to be the same as our recipient_id

[5] pry(#<RSpec::Core::ExampleGroup::Nested_1::Nested_7::Nested_1>)> user.somethings.where(else_id: something.else_id).to_sql
=> "SELECT `somethings`.* FROM `somethings` WHERE `somethings`.`user_id` = 20323 AND `somethings`.`else_id` = 6465  ORDER BY id DESC"
[6] pry(#<RSpec::Core::ExampleGroup::Nested_1::Nested_7::Nested_1>)> user.somethings.for_me.where(else_id: something.else_id).to_sql
=> "SELECT `somethings`.* FROM `somethings` WHERE `somethings`.`recipient_id` = 20323 AND `somethings`.`else_id` = 20323  ORDER BY id DESC

when in doubt read the Rails source

# remove user_id = proxy_association.owner.id from scope
    # so it can be reapplied by to_me or for_me
    def global_scope
-      s = respond_to?(:scoped) ? scoped : all
-      s.where_values = []
-      s
+      unscope(where: :user_id)
    end

which is the way that rewhere reassigns values in where rather than chaining again

2.2.2 :006 > Something.where(user_id: 1).where(user_id: 2).to_sql
=> "SELECT `somethings`.* FROM `somethings` WHERE `somethings`.`user_id` = 1 AND `somethings`.`user_id` = 2"
2.2.2 :007 > Something.where(user_id: 1).rewhere(user_id: 2).to_sql
=> "SELECT `somethings`.* FROM `somethings` WHERE `somethings`.`user_id` = 2"

I like ActiveRecord OR-ing

class Creature < ActiveRecord::Base
    scope :is_good_pet, -> {
        where(
            arel_table[:is_cat].eq(true)
            .or(arel_table[:is_dog].eq(true))
            .or(arel_table[:eats_children].eq(false))
        )
    }
end
GPK of the Day TOMMY Tomb