Sunday, March 15, 2020

Saturday, March 14, 2020

Why Can't I Install Rubies...

It seems installing Rubies has become more of a chore as of late. I mean, why can't I Cut Rubies with ease! like it's advertised on rvm.io?

A wider search on this subject turns up other Ruby installers, such as rbenv, also have the same problem. However, I have found a workaround that seems to work. This discovery is not my original work, but I combed through various articles and forums to come up with it.

Using RVM as an example, let's install Ruby 2.6.5:

$ rvm install 2.6.5
Searching for binary rubies, this might take some time.
No binary rubies available for: osx/10.15/x86_64/ruby-2.6.5.
Continuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.
Checking requirements for osx.
Certificates bundle '/opt/local/etc/openssl/cert.pem' is already up to date.
Requirements installation successful.
Installing Ruby from source to: /Users/salty/.rvm/rubies/ruby-2.6.5, this may take a while depending on your cpu(s)...
ruby-2.6.5 - #downloading ruby-2.6.5, this may take a while depending on your connection...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13.4M  100 13.4M    0     0  2766k      0  0:00:04  0:00:04 --:--:-- 3358k
ruby-2.6.5 - #extracting ruby-2.6.5 to /Users/salty/.rvm/src/ruby-2.6.5.....
ruby-2.6.5 - #configuring......................................................................
ruby-2.6.5 - #post-configuration.
ruby-2.6.5 - #compiling.....................................................................
ruby-2.6.5 - #installing...........
ruby-2.6.5 - #compiling............................
Error running '__rvm_make -j2'
...

The exact error message varies, but as far as I can tell, it always follows the pattern of failure at __rvm_make something. This means an internal call to make has failed. To remedy this, we need to essentially help RVM finish doing its thing by executing the following commands:

$ pushd ~/.rvm/src/ruby-2.6.5
$ make install
$ popd
$ rvm --create 2.6.5
$ rvm cleanup all

Voila! Now Ruby 2.6.5 has been installed.

$ rvm 2.6.5
Using /Users/salty/.rvm/gems/ruby-2.6.5
$ ruby --version
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]

Thursday, July 17, 2014

Why Controller#pre_render?

Recently I was pleasantly surprised that my pre_render methodology still works with Rails 4.1.4, which led me to re-visit and re-answer for myself the question of why it is helpful.

Consider the following Account model. To properly create an account, we need to associate it with a user record:

class Account < ActiveRecord::Base
  belongs_to :user
  validates :user, :presence => true
end

To do so, the following AccountsController#new is necessary:

class AccountsController < AuthenticatedController

  before_action :set_account, only: [:show, :edit, :update, :destroy]

  # GET /accounts/new
  def new
    @account = Account.new
    # Will be used by view to populate a
    # user drop down
    @users = User.all.order(:last_name)
  end

  # GET /accounts/1/edit
  def edit
    # Will be used by view to populate a
    # user drop down
    @users = User.all.order(:last_name)
  end

  # POST /accounts
  # POST /accounts.json
  def create
    @account = Account.new(account_params)
    respond_to do |format|
      if @account.save
        format.html { ... }
        format.json { ... }
      else
        format.html do
          # Needed here again to populate the user
          # drop down in error case
          @users = User.all.order(:last_name)
          render action: 'new'
        end
        format.json { ... }
      end
    end
  end

  # PATCH/PUT /accounts/1
  # PATCH/PUT /accounts/1.json
  def update
    respond_to do |format|
      if @account.update(account_params)
        format.html { ... }
        format.json { ... }
      else
        format.html do
          # Needed here again to populate the user
          # drop down in error case
          @users = User.all.order(:last_name)
          render action: 'edit'
        end
        format.json { ... }
      end
    end
  end

end

The same pattern needs to be repeated for the edit/update actions as well. Which means there are 4 different code paths in which @users needs to be initialized. This problem will grow for models with more complex relationships as well. So wouldn't it be nice if we can have a central place where @user is initialized? We can accomplish this using the #pre_render approach to be DRY-ier:

class AccountsController < AuthenticatedController

  before_action :set_account, only: [:show, :edit, :update, :destroy]

  # GET /accounts/new
  def new
    @account = Account.new
  end

  # GET /accounts/1/edit
  def edit
  end

  # POST /accounts
  # POST /accounts.json
  def create
    @account = Account.new(account_params)
    respond_to do |format|
      if @account.save
        format.html { ... }
        format.json { ... }
      else
        format.html { render action: 'new' }
        format.json { ... }
      end
    end
  end

  # PATCH/PUT /accounts/1
  # PATCH/PUT /accounts/1.json
  def update
    respond_to do |format|
      if @account.update(account_params)
        format.html { ... }
        format.json { ... }
      else
        format.html { render action: 'edit' }
        format.json { ... }
      end
    end
  end

protected

  def pre_render(action)
    case action
    when :edit, :new
      # Will be used by view to populate a
      # user drop down
      @users = User.all.order(:last_name)
    end
  end

end

Pretty nifty!

Thursday, August 15, 2013

Add new page to Rails app documentation

I learnt about rake doc:app in Rails 4.0.0 the other day. Pretty handy stuff. But, it turns out if I wanted to add, say, a CHANGES.rdoc at the same level as README.rdoc, and have it included as a page in the generated HTML output, there is no simple, built-in way to do it.

I know this because I figured out that the doc:app task is part of the railties gem. Opening up its documentation.rake file, I found this code block:

RDocTaskWithoutDescriptions.new("app") { |rdoc|
  rdoc.rdoc_dir = 'doc/app'
  rdoc.template = ENV['template'] if ENV['template']
  rdoc.title    = ENV['title'] || "Rails Application Documentation"
  rdoc.options << '--line-numbers'
  rdoc.options << '--charset' << 'utf-8'
  rdoc.rdoc_files.include('README.rdoc')
  rdoc.rdoc_files.include('app/**/*.rb')
  rdoc.rdoc_files.include('lib/**/*.rb')
}

As you can see, the task only recognizes README.rdoc in an app's top-level directory. But, if I change the code a tiny bit, then it will happily include as many .rdoc files as I create.

RDocTaskWithoutDescriptions.new("app") { |rdoc|
  rdoc.rdoc_dir = 'doc/app'
  rdoc.template = ENV['template'] if ENV['template']
  rdoc.title    = ENV['title'] || "Rails Application Documentation"
  rdoc.options << '--line-numbers'
  rdoc.options << '--charset' << 'utf-8'
  rdoc.rdoc_files.include('*.rdoc') # include all .rdoc files
  rdoc.rdoc_files.include('app/**/*.rb')
  rdoc.rdoc_files.include('lib/**/*.rb')
}

I opened up issue #11903 about this. Let's see how it goes.

Sunday, February 17, 2013

Controller#pre_render

As a follow-up to a previous post about Initialize Instance Variables Needed By A View In One Place, here is a more evolved/elegant approach.

First, I override the render method in app/controllers/application_controller.rb:

# override render so we can call pre_render on child classes

def render(*args)
  if self.class.method_defined? :pre_render
    action = args[0].is_a?(Hash) ? (args[0][:action] || action_name) : action_name
    self.pre_render(action.to_sym)
  end
  super
end

Then, I optionally define the pre_render method in my other controllers:

# define this method so that we can initialize the needed instance
# variables the views need all in one place

def pre_render(action)
  case action
  when :edit, :new
    @users = User.all
  when :show
    @subaccounts = @account.subaccounts.order(:name)
  end
end
Conceptually, this is similar to ASP.NET's PreRender() event handler.

Thursday, February 14, 2013

Linux Myth

I remember one of the knocks against Windows was how often it needs to be patched and rebooted, and that Linux/Unix does not. Well, I am here to say that is a myth. I manage a couple of Ubuntu boxes, and the rate at which patches and reboots come in are just as frequent, if not more so, than the Windows ones I manage.

Wednesday, February 6, 2013

Initialize Instance Variables Needed By A View In One Place

In Rails, should Controller#create fail, the pre-generated code will call render :action => "new". But all too often rendering the new view requires other instance variables to be assigned, which don't get assigned in this execution path if I place the initialization code in the Controller#new method.

I have been frustrated by the lack of a good way to handle it. At first I looked into the presenter pattern, but did not come up with anything that I liked.

Then, I came across this idea, which at first glance, seems to work well. My main goal is to have a good place to initialize the needed instance variables needed by the view only once, and overriding #render seems like a good way to go.

Your thoughts?
# Override this method so that we can initialize the needed
# instance variables the view needs all in one place

def render(*args)
  action = args[0][:action] || action_name
  case action
  when "new"
    @accounts = Account.order(:name)
    ...
  end
end