Ruby Bundler Install Error on Mac OS

I migrated a project a couple of days ago from Fedora to Mac OS. The project uses bundle to install the required ruby gems, and I ran bundle install when I migrated the project, so today I expected it to just work. But it did not.

One of the gems the project uses is sass, and it also uses a watch task in grunt to compile sass files automatically, However, when I edited a file, I got an error. Sass was not installed. I ran bundle install again, and noticed that the command was returning some errors about certain files not being writable. This is because of the ‘rootless‘ feature in Mac OS, which prevents anybody, even root, from writing to certain locations. One of those locations is /usr/bin, which bundle was trying to write to to add the gem executable files. No wonder I was getting a not-istalled error for sass. However, I hadn’t really realize that just jet.

I decided to investigate the issue, and found that some people who had the same problem fixed it by adding certain location to their path. This is when I actually understood what was going on, because even though I had seen the bundle errors, I hand’t really understood the issue. As I said before, bundle was trying to write to a location where it could not. I.e. /usr/bin.

I did some more researching and found some information about the gemrc file, and how it can be used to tell gem where it should install gems. I created a gemrc file, and tried bundle install. The error didn’t get fixed.

I decided to look for the documentation for bundle install, and there I found that you can specify where gems should be placed, and where the executable files should be placed. I finally ran the command

bundle install --force --path=~/ --binstubs=~/bin

It failed with error

Errno::EACCES: Permission denied @ rb_sysopen – /Users/me/bin/bundle
An error occurred while installing bundler (2.0.0), and Bundler
cannot continue.

AT this point I was loosing hope, and getting frustrated, but I continued looking for an answer. That is how I found that I probably had the wrong permissions for bundle. I listed the contents of my ~/bin directory, and found that the bundle file was owned by root. I changed ownership of the file to me, and this finally got everything working correctly.

It may seem like I fixed this issue in no time, but the reality is that I spent over two hours trying until finally being able to make it work. I should say, though, that I am no ruby developer. This project is the only place were I’ve ever used bundle, and gems that I can think of. Plus, I’m finding out that the ‘rootless‘ feature is at a minimum as annoying as selinux, but I would never, ever, advice anybody to disable it, nor would I do it in my own computer:

Advertisements

Setting Up Canon G3111 on Mac OS Mojave

Today I was setting up the home printer on the Mac OS Mojave machine, and, although there is a driver download page from canon, there is no download button, or at least I  couldn’t find one. The printer doesn’t seem to support AirPrint, and none of the other options in the printer settings seemed to work. The solution: find a driver.

A quick search got me to this page https://ijcanon.com/canon-pixma-g3110-drivers-download/ where I selected the CUPS driver for Mac OS, and went through the set up process. After that was done, I went to system preferences > Printers & Scanners, and clicked the plus button. The printer was listed in the Default section, and I selected it as I had been doing previously, and again, no driver was auto-selected for it. I selected the “Select software” option in the section labeled “Use”, and this time, there was a G300 driver option on the list that appeared. That option wasn’t there previously. I selected that, and Clicked Add to add the printer. The printer is now set up and working.

Drupal Error: PDOException: SQLSTATE[42000]: Syntax error or access violation: 1231 Variable ‘sql_mode’ can’t be set to the value of ‘NO_AUTO_CREATE_USER’ in lock_may_be_available()

I was setting up a drupal 7 site on a Mac OS computer, and got the error in the title when trying to sync the local DB with a remote DB. After a lot of time, the problem came down to a mysql incompatibility. I had installed MySQL 8, and had to downgrade to MySQL 5.7.24. The full error message contained a reference to the file includes/loc.inc line 167 as the source of the exception, but scrolling a little up the file I saw a catch statement in the lock_acquire function, and decided to dump the error caught. It turns out the exception is actually thrown on file includes/database/mysql/database.inc, line 94, in the constructor of the DatabaseConnection_mysql object. In the constructor is where Drupal tries to set sql_mode to a value which MySQL 8 is rejecting. For more information visit https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html#mysql-nutshell-removals

The Weird Case of the Modem that Would Work With Only One of the Devices Connected to It.

I received a message this morning from my brother, who said to be having problems with his modem. He said, that all the sudden all the devices connected to it stopped getting internet service, except for one. The devices seemed to be connected, but the internet would not work on any of them, except for the Roku they use to make their TV a little smarter. I said I would stop by to check it later, and so I did.

Just like he had explained, only the Roku could connect to the internet. My initial thought was that the Roku, for some reason was hugging the internet all for its own, so I disconnected it, and nothing changed. The other devices still were unable to connect to the internet. I knew for sure that the devices were connected and that the modem was recognizing them because I could see them in the modem’s settings panel.

I must have spent over half an hour looking at all the settings in the modem over and over, changing channels, and other settings with no luck. When I was about to give up, it occurred to me that it could be a DNS issue. This right after my brother demonstrated how WhatsApp was the only internet app that seemed to work. I updated the DNS in a Mac we had wired to the modem, and just as I hit the Apply button, a bunch of notifications and what not started showing up in the screen. Vioala!

I adjusted the DNS settings on the modem, and then all the connected devices started working well. I don’t know who his ISP is, and why in the world their DNS would stop working, but I’m glad there are open DNS servers. As far as for why the Roku was the only device that was working well, it seems Roku uses custom DNS.

Debugging Apache Virtual Host Config

This is just a quicktip I found while doing a quick search for the sintax for a virtual host in apache: You can run apachectl -t -D DUMP_VHOSTS to run config test for virtual hosts. This will report any error there may be with your config. I found this is a great way to debug virual host config files. You can read more about apachectl on https://httpd.apache.org/docs/current/programs/apachectl.html

Properly Triggering Vue Component Lifecycle Hooks

This is something that got me scratching my head for a little while: If I have a vue component with a mounted hook, how can I trigger that hook every time the component is updated?

The first thought is, if you want a hook that triggers every time the component is updated, you need an updated hook, but that is not always the case. Here is my particular case:

I have a component that renders a list of options. For example, a list of venues. Each venue in turn has a list of sections. The list of sections is managed by another component, and they share data through a parent component. So far we have a parent component that owns the list of venues, and the list of sections.

When the user clicks on a venue, the parent is notified via a custom event, and it updates data that is passed to the list of sections (the venue info). The list of sections component uses this data to fetch the actual list of sections from the server. It does that through a mounted hook. The reason for not passing the list of sections to the component through a prop is that the component should be responsible for fetching that list so that the functionality is encapsulated.

The problem is that the hook will run only once the first time the user clicks on a venue. After that, the venue information it receives from its parent will be updated, but that won’t trigger the mounted hook. We could use an update hook, but since fetching the list of sections from the server will eventually update the component, we would enter an infinity loop. At this point we need a way to re-run the mounted hook, but how?

The solution is to use a key attribute on the sections component, and update it when the venue information is updated, i.e. when the user clicks on a venue. We could use, for example venue.id as the key value. This is because changing the key attribute tells vue that the component should be treated as a new instance.

For more information, read the documentation for key https://vuejs.org/v2/api/#key

Sending e-mails: Fedora 29, Apache, & Php

In the past, I’ve touched on the subject of how to set up a localhost to send emails. At some point it was enough with just installing postfix and following a few prompts. Then port 25 was blocked by the ISP and it was necessary to set up a postfix to use an external SMTP server. Now, on Fedora 29 I wanted to enable e-mail sending using php’s mail function. It took me  a full day to do it, but finally got it working. It is worth mentioning that this time I didn’t want to set up postfix to use an external SMTP server, although I did try using postfix, but as the logs revealed, port 25 is blocked by my ISP.

One thing to note, that actually cost me a lot of time, is that you won’t find a mail log file in Fedora 29. Fedora uses journal from systemd to do logging now, so you will have to use journalctl to view the logs. Reviewing the logs is how I found out that postfix was timing out when trying to send emails.

In any case, my idea wasn’t really to use postfix. Fedora 29 ships with esmtp which is a “send-only sendmail emulator” according to the man page. The nice thing about it, is that you should only have to make a .esmtprc file on your home directory with the remote SMTP server information. This worked great. I could send emails using `mail` in the command line, and I could even fire up php -a and use the mail function to send out emails. Everything was great until I tried to send emails from one of my locally hosted dev sites (finally getting around to build buzu.me lol). The email was never even accepted for deliver, as denoted by the false value returned by the mail function.

In order to investigate this matter, I decided to try to send emails as the apache user from the command line. This resulted in a error. The command complained about not being able to create a .esmtp_queue directory on /usr/share/httpd/. I decided to manually create it, and make apache the owner of it. I tested again, and it worked! You should know that at this time my esmtprc is now located at /etc/ so that apache can use it. I suppose I could create at .esmtprc file in the httpd directory, but I haven’t tried that.

I knew now that apache could send emails, so I decided to check again using the locally hosted site, and no luck. mail continued to return false, indicating that the email wasn’t even accepted for delivery. At this point, the only time the mail function returned true was when I used postfix, but I had decided not to use it since esmtp is made specifically for the purpose I intended.

One thing had changed though. Before I manually created the queue directory for the apache user, the mail function simply failed, but now, selinux was displaying an alert, but when I tried to open it, it was blank. I remembered that at some point I had seen an SELinux entry in the logs, so I decided to re-visit the logs and look for a similar entry. I found this:

***** Plugin catchall_labels (83.8 confidence) suggests *******************

If you want to allow mktemp to have write access on the .esmtp_queue directory
Then you need to change the label on .esmtp_queue
Do
# semanage fcontext -a -t FILE_TYPE '.esmtp_queue'
where FILE_TYPE is one of the following: admin_home_t, courier_spool_t, etc_aliases_t, etc_t, exim_log_t, exim_spool_t, mail_home_rw_t, mail_home_t, mail_spool_t, mqueue_spool_t, munin_var_lib_t, postfix_etc_t, qmail_spool_t, sendmail_log_t, system_mail_tmp_t, tmp_t, user_home_dir_t, uucpd_spool_t, var_log_t.
Then execute:
restorecon -v '.esmtp_queue'

***** Plugin catchall (17.1 confidence) suggests **************************

If you believe that mktemp should be allowed write access on the .esmtp_queue directory by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'mktemp' --raw | audit2allow -M my-mktemp
# semodule -X 300 -i my-mktemp.pp

I decided to change the context to mail_home_rw_t and tried again. It worked.

It is worth noting that at some point I also did setsebool httpd_can_sendmail=1. Without that, httpd can’t use sendmail,

The Wordpress Auto Draft

Disclaimer: I’ve been away from the wordpress world for over a couple of years now, so I don’t know if this is common knowledge in the wordpress circles or not. Heck! I don’t even know if this is something that has always happened, or if it is something that was implemented while I was away from WP, but it is definitely something that threw me off a bit recently.

After some time away from WP, I decided it was time to go back and try all the new features that have arrived to WP since I left it a while back. I started developing a small webapp. I know I could have used something better suited for the task, like Laravel, but the goal here is to get WP to do something that clearly stretches its limits. One of the things I wanted to do was to assign an ID to custom-type posts. I didn’t want to rely on the post’s id, but rather create an md5 hash of the post’s title. The key part was to create it when the post was first created and then never change it again, even if the title changes. The post’s id would have suffice, but remember that this is an exercise to get back into wordpress development.

My first instinct was to use the `save_post_{$post->type}` action hook. This action passes a boolean parameter to the callback function that specifies if the post being saved is an update of an existing one. If it isn’t, we can assume the post being created is brand new. Relying on this boolean seemed like the obvious choice since it would allow me to save the md5 hash only once when the post is first created, and never touch it again. So, I did it this way. However, later, when I decided to display a custom row in the all-posts table that displayed the post’s custom id, I realized that all the posts had the same custom id. How was this possible? Digging into wordpress I found out that every time you open the new post page, a new post is saved in the database with title “Auto Draft” so all my md5 hashes were being generated from that “Auto Draft” title. No wonder they were all the same!

So, how does this happen?

When you first open the new post page (post-new.php) a function named `get_default_post_to_edit` is called, which, among other things, creates a new post in the DB, creates a new post object for it, and passes it along to other functions and hooks. This is actually a good thing because it makes sure you are always working with a real post object that has a DB record, and an ID. However, if you aren’t aware of it, it may get you scratching your head for a little while when something doesn’t happen as you’d expect it to happen. Knowing these kind of subtleties is what makes the difference between a good, and excellent developers.

Read, the docs, but more importantly, read the codes!

Nested Form Input in Drupal

HTML forms are made up of input controls that, when submitted, are converted into an array of values. For example, consider the following form:

<form method="post" action="/">
<input type="text" name="input1" />
<input type="text" name="input2" />
<input type="submit" name="send" value="Send" />
</form>

When a user fills out this form, and submits it, the data is sent by the browser using the POST HTTP method in this fashion:

input1: value
input2: value
send: send

If you were to read that with PHP, you would have to access the `$_POST` array, which would contain those key-value pairs. However, some forms are complex enough that flat arrays like that make it hard to work with the data. In those cases it is useful to get multidimensional arrays. HTML allows you to do just that:

<form method="post" action="/">
<input type="text" name="persons[0][name]" />
<input type="text" name="persons[0][address]" />
<input type="text" name="persons[1][name]" />
<input type="text" name="persons[1][address]" />
<input type="text" name="persons[2][name]" />
<input type="text" name="persons[2][address]" />
<input type="submit" name="send" value="Send" />
</form>

In PHP that results in the following `​$_POST` array

Array
(
 [persons] => Array(
   [0] => Array(
     [name] => john
     [address] => smith
   )
   [1] => Array(
     [name] => jane
     [address] => doe
   )
   [2] => Array(
     [name] => jason
     [address] => foo
   )
 )
 [send] => send
)

As you can see, the information for `persons` is now nicely arranged in an array of arrays, each of which contains the information associated with a person.

If you want to replicate that same structure in Drupal, it is quite easy. Using the Drupal Form Api you can easily create form arrays that Drupal knows how to render. But those forms usually submit data in the flat array form. If you want to get multidimensional array like we did above, you need to use the `#tree` attribute on the element that you want to be the root array member. For example, to get the same input we have above, you would do something like:

$form = [
  'persons' => [
    '#type' => 'markup',
    '#tree' => TRUE,
    '0' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
    '1' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
    '2' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
  ],
];

If you were to omit the `#tree` attribute on the `persons` element in the form array, you would get a flat array of values with name, and address values for the last input fields only. Also note that the nested arrays begin at the point where the `#tree` attribute is specified. For example, if `persons` was itself a child of another element called `personal_data`, the resulting POST data wold remain the same, unless the `#tree` attribute was specified in the `personal_data` element, in which case, the `persons` array would also be child to a `personal_data` member in the `values` array where Drupal saves the submitted data when dealing with form submissions.