Today I Learned

A Hashrocket project

15 posts by micahcooper @mrmicahcooper

Create a Placeholder for Content Editable Divs

When you have a content editable div. Add an data attribute. We’re going to use placeholder:

<div contenteditable="true" data-placeholder="(untitled)" class="title">
</div>

Then in your css, use a few pseudo classes to make it behave like a placholder:

.title:empty:not(:focus):before {
  content: attr(data-placeholder)
}

Very cool! I (for whatever reason) never knew about :empty, :not, attr() or chaining multiple pseudo classes. Learned a lot in this little snippet :)

h/t @alejandroRINC0N

Simplify System.cmd with W sigil

Say we have the following shell command to get the the unix timestamp of the last commit:

$ git log -1 --date=short --pretty=format:%ct

1470067380

In elixir. One might do it like so:

System.cmd("git", ["log", "-1", "--date=short", "--pretty=format:%ct]) 
|> elem(0)

#=> "1470067380"

And here is just a simpler syntax for the same thing:

System.cmd("git", ~w[log -1 --date=short --pretty=format:%ct])
|> elem(0)

#=> "1470067380"

This is just a little clean and feels more like the original command.

You Can Git Push to an SSH Alias

When we are using Git via ssh, we can take full advandage of our ssh conveniences.

So, lets say we have some ssh coniguration in our .ssh/config

Host til-production
  Hostname 11.22.333.44
  User ubuntu

Now we ssh into our server and create a bare repository.

ssh til-production
mkdir ~/til
cd ~/til
git init --bare

Then back on our local machine, instead of adding a remote with:

git remote add production ubuntu@11.22.333.44:til

we can simply:

git remote add production til-production:til

It’s a little bit less to think about.

h/t @vidalekechukwu

Named Captures with Elixir Regular Expressions

I can’t believe I’m just now learning about this! How neat!

iex(0)> string = "Here is my phone number: 999-111-1234"
"Here is my phone number: 999-111-1234"
iex(1)> regex = ~r/number: (?<phone>[\d|-]+)/
~r/number: (?<phone>[\d|-]+)/
iex(2)> Regex.named_captures(regex, string)
%{"phone" => "999-111-1234"}

Write a regex capture with ?<> in the beginning and get back a map of your captures with Regex.named_captures/2

Find and Open Port with Elixir

iex(1)> {:ok, port} = :gen_tcp.listen(0, []) #listen on an available port
{:ok, #Port<0.1465>}
iex(2)> {:ok, port_number} = :inet.port(port) #get the port number of that port
{:ok, 63470}
iex(3)> port_number #here is the port number!
63470
iex(4)> Port.close port #go ahead and close that port if you want
true

Useful for maybe automating the deployment of a plug app.

Transform values when using SweetXML xmap

Assume I have the following XML


xml = """
<response>
  <users>
    <user>
      <firstName>Micah</firstName>
      <lastName>Cooper</lastName>
    </user>
    <user>
      <firstName>Joe</firstName>
      <lastName>Hashrocket</lastName>
    </user>
 </users>
</response>
"""

I can write a small module to map this to something really cool.

defmodule XmlMapper do
  import SweetXml
  @schema [
      names: [ ~x[//response/users/user]l,
        name: ~x[concat(./firstName, " ", ./lastName)]s |> transform_by(&String.upcase/1)
      ]
    ]

  def map(xml_string) do
    SweetXml.xmap(xml_string, @schema)
  end
end

.map will find a list of user elements, concatenate the firstName and lastName, then upcase the whole thing and return it in a map.

iex> XmlMapper.map(xml)
%{names: [%{name: "MICAH COOPER"}, %{name: "JOE HASHROCKET"}]}

That’s doing a lot with a little.

Ruby Retry- Where you been?

For some reason, I never knew about ruby’s retry keyword. The more you know…

def api_request
  TwitterWrapper.make_request # Throws a ServiceUnavailabe(506)- Server overloaded
 rescue ServiceUnavailable => error
    retries = retries.to_i + 1 # Increment a retry counter
    retries < 5 ? retry : raise(error) # run the method again until "retries is exceeded"
    # notice the local variable "retries" is persisted through retries
end

You could put a sleep in there if you wanted to wait a certain amount of time before retrying.

h/t Vinicius Negrisolo

Strong Parameters with arrays

Need to permit a strong parameter that can either be an array or a string? Just permit it twice!

# This is just for shortened syntax for this TIL.
class Param < ActionController::Paramaeters
end 

Param.new({foo: "bar"}).permit(:foo) 
#=> { "foo" => "bar" }
Param.new({foo: "bar"}).permit(foo: []) 
#=> { }

Param.new({foo: ["bar"]}).permit(foo: []) 
#=> { "foo" => ["bar"] }
Param.new({foo: ["bar"]}).permit(:foo)
 #=> { }

Param.new({foo: ["bar"]}).permit(:foo, foo: [])
 #=> { "foo" => ["bar"] }
Param.new({foo: "bar"}).permit(:foo, foo: [])
 #=> { "foo" => "bar"}

Return an Empty Active Record Collection

You can use .none in a scope to short circuit the query in the event you don’t have all the data.

Imagine this query but the project_type on a Project is nil


class User

  scope :active -> { where(archived: nil }

  scope :by_project, -> (project) do
    return none unless project.type.present?
    where(project_guid: project.guid, role: project.type)
  end

end

Just return none.

The cool thing about this is it’s chainable. So you can still do something like:


project = Project.new(project_type: nil)

User.by_project(project).active

Add a UUID Datatype to Your Rails App

Create a migration to add the extension


class CreateUuidExtension < ActiveRecord::Migration
  def change
    create_table :uuid_extensions do |t|
      enable_extension 'uuid-ossp'
    end
  end
end

Add a column to your table with a data type of :uuid. Don’t forget to add a default of uuid_generate_v4()

class AddUuidToAccounts < ActiveRecord::Migration
  def change
    add_column :accounts, :uuid, :uuid, default: 'uuid_generate_v4()'
  end
end