highlander

The Highlander query with Rails’ ActiveRecord

For those cases in which there can be one and only one record on the database with certain fields and I don’t just want to get the first one and silently get the wrong one. I want to make sure there’s one and only one, so, I wrote this little extension to ActiveRecord that does exactly that:

module ActiveRecordExtension
  extend ActiveSupport::Concern

  class_methods do
    def one_and_only
      records = limit(2).all.to_a
      if records.count > 1
        raise "#{self} generated more than one record when expecting only one."
      else
        records.first
      end
    end

    def one_and_only!
      one_and_only.tap do |record|
        if record.nil?
          raise "#{self} didn't generate any records."
        end
      end
    end
  end
end

ActiveRecord::Base.send(:include, ActiveRecordExtension)

The first method, one_and_only, will raise an exception if there’s more than one item but it’ll return null if there aren’t any. one_and_only! will fail if there isn’t exactly one and only one record in the database.

If you don’t know why I’m calling this The Highlander query, you should go and watch Christopher Lambert’s masterpiece.

screensaver-ninja-component-architecture-for-blog-background

Screensaver Ninja will be very different this time

After my announcement of Screensaver Ninja’s potential return, many people asked for features and more information. I answered all emails individually but there are some things I want to share with everybody.

I’m rewriting Screensaver Ninja from scratch with a completely different architecture to cover the two most requested features:

  • Microsoft Windows support
  • Centralized management of many installations

Most of Screensaver Ninja will be developed using cross platform technologies and it’ll have several components:

Screensaver Ninja component architecture.png

This breakdown in components exist to make the most complex deployments possible but I’ll provide packaged solutions for the simple cases.

The configurator is the first app you start. This one allows you to create an account and set up which web sites to show and in which machines. The account is created on a hosted server I’ll be providing and this time Screensaver Ninja will be SaaS, that is, software as a service, with a monthly or yearly subscription.

The displayer components are the ones you run in the machines you want to display the web pages. Displayers will include screensavers for Mac and Windows, but also standalone applications, live wallpapers, iOS and Android apps, etc.

The displayers will never contain any cookies or credentials so you can put them in lower security machines without worrying that person gaining or having access to that machine will gain access to your web applications. This is achieved by shipping screenshots to the displayer.

The screenshots are generated by another component called renderer. These will get the cookies and credentials but you only need one for your whole organization and it can run in a secure environment, such as the computer of a trusted person or even a server in a data center. You may also have more than one renderer to distribute the load and ensure availability.

A single computer can run all components if you are a solo Screensaver Ninja user.

Cookies and credentials will be end to end encrypted so only the configurator and the renderers will have access to them. Screenshots will be encrypted so that the displayers have access. This ensures that I don’t have access to your private data and should my servers be compromised, the attackers won’t have your data either.

This sequence diagram shows the flow of data through the different components:

Screensaver Ninja architecture.png

What do you think? Does this suit your needs?

background

Screensaver Ninja might be coming back

Since discontinuing Screensaver Ninja, I have received many messages asking when it is coming back: over Twitter, Facebook, email, and even one person tracking me down on Reddit..

For those of you who don’t know what Screensaver Ninja is, here is the old explainer video:

It has been very painful to read these messages for a couple of reasons. Firstly, I strongly believe in the product. I want to have it; use it; and enable others to use it. I constantly see expensive and badly designed dashboards or wasted screens, which my product will address. Secondly, judging by the requests, other people want this just as much as I do. Not proceeding with Screensaver ninja could be a wasted business opportunity; although it is hard to tell if the demand is enough to support its development right now.

I set up a landing page explaining what happened to Screensaver Ninja and a form for people to register for notifications of its potential comeback. This was a way to save everybody’s time and frustration; for those emailing requests for up to date information when I could only say, with sadness, “it’s over”. To my surprise, this form has been gathering five or so leads a week, which is rather a lot for an abandoned product.

I have started playing with the idea that I might revive Ninja: This time I have designed a bigger system that covers many more use cases and allows me to support both Windows and Mac OS as well as other platforms just as easily.

During this process I identified the technological bottlenecks; the aspects to product creation that can take months to negotiate and solve, such as hacking Apple’s cookie jar or packaging Chromium. In doing so, I have built a selection of prototypes testing my choices – and everything is working beautifully.

So that’s it: I have decided to revive Screensaver Ninja. I have emailed all of you whom have shown interest to tell you the good news, and have received an overwhelmingly positive response from both individuals and corporations; some wanting to run hundreds of instances.

I want to be completely transparent with my supporters; I am building Screensaver Ninja by myself in my spare time between long days and after hours work at two different consultant gigs. Whilst I am looking into the options of partnerships, developers, and marketers, I have decided not to wait for these additions to the team in order to make progress. I’m very excited about this phase both from the technical as well as the business points of view so Screensaver Ninja is moving forward and I will have frequent updates.

Going into the property business 

I’m a tech entrepreneur and that has not changed, but after six or seven years of trying to have at least moderate success, I’m starting to hedge my bets.

On the side, I want to have some passive income and it looks to me like buy and hold properties, that is, buying them and renting them out, also known as buy to let, is the way to move forward. I identified some very profitable areas and they are in the least expected places. For example, in London you can expect a return on investment of around 3% while I’m getting something around 16%.

If you want to listen to my journey, I’m documenting it as I go with Clayton Morris on his podcast about investing in property. He just published the second episode in which I talk about getting the money for my first two deals.  I just pulled the trigger on starting the business. I’m super excited and I can’t wait to share more good news in the next episode. 

emacs

Emacs is hurting Clojure 

Emacs is a very powerful text editor and its popularity amongst Clojurians is easily understood. Emacs has a long tradition in the Lisp communities as it’s written, in a big part, in a flavor of Lisp called Emacs Lisp.

Because of its history, it handles Lisp code wonderfully, with automatic correct indentation, paraedit, integration with REPLs, etc. But Emacs is really hard to use.

Yeah, most Clojurians know how to use it by now and they suffer from bias: “it’s not that hard” they say. Learning Emacs or Clojure is hard enough. Combining them is insane.

Many Clojurians also say it’s worth it. And again, I think they are biased. Human brains are very good at forgetting pain. Other editors these days are also very powerful and although not as much as Emacs, their usage is intuitive so you can achieve a higher level of proficiency just by using it, without spending time and effort in becoming better at it.

The way Emacs is hurting Clojure is by Clojurians maintaining this myth that you need to use Emacs for Clojure. This is not done by simple statements but by a general culture of jokes saying things such as “you are wrong if you don’t use emacs”.

Me, personally, I don’t care what editor you use. If you want to learn Emacs, go for it. Intellij and Cursive is much easier to use and almost as powerful. When I compare myself to another clojurian, productivity is generally decided by knowledge of the language and libraries, not the editor. If you want to use another editor, so be it. It’s better if they understand Lisp code but it’s not a deal breaker for learning Clojure.

I do care about the success and popularity of Clojure. Coupling the growth of the language to the use of an editor that is hard to use and non intuitive makes no sense. It’s hurting us. Even if you are an Emacs power user, when you talk to a Clojure newbie, please, don’t push it down their throats.

Thank you.

Avoiding threads of emails when developing a Rails application

Call to Buzz, like many applications I developed before, sends emails. Lot’s of emails. To avoid accidentally emailing a customer or random person I use mail_safe. It’s one of the first gems I install on a Rails project and you should too. mail_safe re-writes the to-header so you end up receiving all the emails that you sent.

Once you are receiving all these emails, there’s another problem. They are likely to have exactly the same subject, so, mail clients are likely to group them in threads, which can be annoying. To avoid that, I added this to my ApplicationMailer class and voila! all emails have a unique subject:

if Rails.env.development?
  after_action :uniq_subjects_in_development

  def uniq_subjects_in_development
    mail.subject += " #{SecureRandom.uuid}"
  end
end

Displaying Delayed::Job’s jobs in Active Admin

I’ve been using both Active Admin and Delayed::Job for years now and both have served me very well. It’s very common for me to want to display job records in the admin tool and have some extra tools around them such as:

  • the ability to mark them all for re-run
  • the ability to run one manually (not recommended for production)
  • the ability to run them all manually (also not recommended for production)
  • an easy way to delete them all
  • a good view of the data inside the job

To achieve this, over the years, my admin/delayed_job.rb grew and I took it from project to project. Today I want to share it with you in case you are doing the same:

ActiveAdmin.register Delayed::Job, as: "DelayedJob" do
  collection_action :run_all, method: :post do
    successes, failures = Delayed::Worker.new.work_off
    if failures > 0
      flash[:alert] = "#{failures} failed delayed jobs when running them."
    end
    if successes > 0
      flash[:notice] = "#{successes} delayed jobs run successfully"
    end
    if failures == 0 && successes == 0
      flash[:notice] = "Yawn... no delayed jobs run"
    end
    redirect_to admin_delayed_jobs_url
    I18n.locale = :en # Running delayed jobs can mess up the locale.
  end

  if Rails.env.development?
    collection_action :delete_all, method: :post do
      n = Delayed::Job.delete_all
      redirect_to admin_delayed_jobs_url, notice: "#{n} jobs deleted."
    end
  end

  collection_action :mark_all_for_re_run, method: :post do
    n = Delayed::Job.update_all("run_at = created_at")
    redirect_to admin_delayed_jobs_url, notice: "Marked all jobs (#{n}) for re-running."
  end

  member_action :run, method: :post do
    delayed_job = Delayed::Job.find(params[:id])
    begin
      delayed_job.invoke_job
      delayed_job.destroy
      redirect_to admin_delayed_jobs_url, notice: "1 delayed job run, apparently successfully, but who knows!"
    rescue => e
      redirect_to admin_delayed_jobs_url, alert: "Failed to run a delayed job: #{e.to_s}"
    end
    I18n.locale = :en # Running delayed jobs can mess up the locale.
  end

  action_item do
    links = link_to("Run All Delayed Jobs", run_all_admin_delayed_jobs_url, method: :post)
    links += (" " + link_to("Mark all for re-run", mark_all_for_re_run_admin_delayed_jobs_url, method: :post)).html_safe
    links += (" " + link_to("Delete All Delayed Jobs", delete_all_admin_delayed_jobs_url, method: :post)).html_safe if Rails.env.development?
    links
  end

  index do
    selectable_column
    id_column
    column "P", :priority
    column "A", :attempts
    column("Error", :last_error, sortable: :last_error) { |post| post.last_error.present? ? post.last_error.split("\n").first : "" }
    column(:created_at, sortable: :created_at) { |job| job.created_at.iso8601.gsub("T", " ") }
    column(:run_at, sortable: :run_at) { |post| post.run_at.present? ? post.run_at.iso8601.gsub("T", " ") : nil }
    column :queue
    column("Running", sortable: :locked_at) { |dj| dj.locked_at.present? ? "#{(Time.now - dj.locked_at).round(1)}s by #{dj.locked_by}" : "" }
    actions
  end

  show title: -> (dj) { "Delayed job #{dj.id}" } do |delayed_job|
    panel "Delayed job" do
      attributes_table_for delayed_job do
        row :id
        row :priority
        row :attempts
        row :queue
        row :run_at
        row :locked_at
        row :failed_at
        row :locked_by
        row :created_at
        row :updated_at
      end
    end

    panel "Handler" do
      begin
        pre delayed_job.handler
      rescue => e
        div "Couldn't render handler: #{e.message}"
      end
    end

    panel "Last error" do
      begin
        pre delayed_job.last_error
      rescue => e
        div "Couldn't render last error: #{e.message}"
      end
    end

    active_admin_comments
  end

  form do |f|
    f.inputs("Delayed job") do
      f.input :id, input_html: {readonly: true}
      f.input :priority
      f.input :attempts
      f.input :queue
      f.input :created_at, input_html: {readonly: true}, as: :string
      f.input :updated_at, input_html: {readonly: true}, as: :string
      f.input :run_at, input_html: {readonly: true}, as: :string
      f.input :locked_at, input_html: {readonly: true}, as: :string
      f.input :failed_at, input_html: {readonly: true}, as: :string
      f.input :locked_by, input_html: {readonly: true}
    end

    f.buttons
  end

  controller do
    def update
      @delayed_job = Delayed::Job.find(params[:id])
      @delayed_job.assign_attributes(params[:delayed_job], without_protection: true)
      if @delayed_job.save
        redirect_to admin_delayed_jobs_url, notice: "Delayed job #{@delayed_job} saved successfully"
      else
        render :edit
      end
      I18n.locale = :en # Running delayed jobs can mess up the locale.
    end
  end
end