Ruby 2.0 with Other Versions

Ruby 2.0.0 came out today and I thought I'd install it. I had been using rvm to handle my multiple versions of ruby, but when I tried to do a rvm install 2.0.0, I got a bunch of errors about homebrew. It seems as though homebrew is now required. This is a problem for me because I've been using MacPorts for years and I just don't feel like switching right now. So, I figured that I'd just see if I could compile it myself by hand and come up with a way to have multiple versions of ruby. The thing is, I really don't switch between versions all that much. I will now, as I slowly convert all the sites I have to 2.0. So I'll need to go back and forth a little. But once it's done, I probably won't switch for a long time. I've been on 1.9.3 for a very long time and it worked fine. Anyway, I'm not exactly sure how I'll do this, but I'm going to give it a try.

First step, was to update XCode and then go into Preferences and update the command-line tools. In the ruby download, my config command was pretty basic:

ant:ruby-2.0.0-p0 $ ./configure --prefix=/Users/maryh/Software/rubies/2.0.0-p0

Putting everything in a Software/rubies/version directory seems to be a good idea. I could be completely wrong about this, but that's how I'm starting. My first make attempt failed with an error like this:

compiling ./missing/setproctitle.c
compiling dmyext.c
linking miniruby
/Users/maryh/Downloads/ruby-2.0.0-p0/lib/fileutils.rb:111: [BUG] Stack consistency error (sp: 38, bp: 36)
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.2.0]

-- Crash Report log information --------------------------------------------
...

I needed to set CC=clang (it was CC=gcc-4.2) and that fixed this problem.

New error:

compiling readline.c
readline.c:1688:9: error: use of undeclared identifier 'username_completion_function'; did you mean
      'rl_username_completion_function'?
                                    rl_username_completion_function);
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                    rl_username_completion_function
readline.c:75:42: note: expanded from macro 'rl_username_completion_function'
# define rl_username_completion_function username_completion_function
                                         ^
/usr/local/include/readline/readline.h:449:14: note: 'rl_username_completion_function' declared here
extern char *rl_username_completion_function PARAMS((const char *, int));
             ^
1 error generated.

Readline errors are apparently common. Again, I'm pretty sure this is related to the fact that I'm using MacPorts. My fix was to:

ant:ruby-2.0.0-p0 $ export LDFLAGS="-L/opt/local/lib"

Then rerun configure and make and things worked. Everything is installed in /Users/maryh/Software/rubies/2.0.0-p0. And the gem environment is:

ant:bin $ ./gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 2.0.0
  - RUBY VERSION: 2.0.0 (2013-02-24 patchlevel 0) [x86_64-darwin12.2.0]
  - INSTALLATION DIRECTORY: /Users/maryh/Software/rubies/2.0.0-p0/lib/ruby/gems/2.0.0
  - RUBY EXECUTABLE: /Users/maryh/Software/rubies/2.0.0-p0/bin/ruby
  - EXECUTABLE DIRECTORY: /Users/maryh/Software/rubies/2.0.0-p0/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-darwin-12
  - GEM PATHS:
     - /Users/maryh/Software/rubies/2.0.0-p0/lib/ruby/gems/2.0.0
     - /Users/maryh/.gem/ruby/2.0.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - http://rubygems.org/

So, now I think I can just install gems there and see how things go.

More Ruby Notes

I just found out that these two ruby commands do the same thing.

Part.order(:category).map(&:category)

and

Part.order(:category).pluck(:category)

Both of these things get all the entries in the parts table, sorts them by the category field and then creates an array of just the category fields. The pluck version is, I think, the newer way and only came about since a relatively recent version of ruby. However, I understand how this works completely. The map version with the & in front of category is confusing to me. Or I could just say, that I don't know what the & does, which would be more true. I'll probably have to look that up at some point, but for now, I'm just using pluck which does what I want it to.

Rails3 form_for vs form_tag

I've been advancing a little in my rails work, to the point where I'm making more elaborate forms. So I've had to switch to using form_tag instead of the form_for that's the default when you use scaffolding. I have a pretty good understanding of the differences now, so I'm documenting it here.

Typically, form_for is used with an instance method that's an item in the table. A simple example from one of my apps is a user account. Ignoring the password checks, I store a username and a fullname in the database table.

Form View (very simplified)

<%= form_for(@user) do |f| %>
  <%= f.text_field :username %>
  <%= f.text_field :fullname %>
  <%= f.submit %>
<% end %>

Now, if I submit that form, I see this in the log file.

 Parameters: {"utf8"=>"?", "authenticity_token"=>"+L5dwW/yTTgVD2i6izN6iP6vGP1PU6y9u3jmgQOih8c=", "user"=>{"username"=>"john", "fullname"=>"John Smith"}, "commit"=>"Create User"}

So, in my users_controller, the create method takes the params for user, makes a new user and saves it.

def create
  @user = User.new(params[:user])
  if @user.save
    redirect_to @user, notice: 'User was successfully created.'
  else
    render action: "new"
  end
end

Now, if I instead use a form_tag things work a little differently. I have a parts table that, for simplicity, say takes a category and size. Using a form_tag, the view looks like this:

<%= form_tag create_part_path, :method => :post %>
  <%= text_field_tag :category %>
  <%= text_field_tag :size %>
  <%= submit_tag %>
<% end %>

First note that I'm not making the form for a particular instance variable. Instead I'm saying that this is a form that I want to post and run the create_part method. What is the create_part method? It's simply the create method in my parts controller. However, since I want to call it by name, I had to name the route (the create and update routes are usually not named) in my routes file. So I added these lines to routes.rb:

match 'parts/' => 'parts#create', :via => :post, :as => :create_part
match 'parts/:id' => 'parts#update', :via => :put, :as => :update_part

So now, when I post this form, in the logs, I see this:

Parameters: {"utf8"=>"?", "authenticity_token"=>"+L5dwW/yTTgVD2i6izN6iP6vGP1PU6y9u3jmgQOih8c=", "category"=>"window", "size"=>"7x7", "commit"=>"Save changes"}

Notice that the params aren't in a part hash, but are just there individually. So now I have to work on the create method.

If this were just a scaffold, the first line in the create method would look like this:

@part = Part.new(params[:part])

In order to fix this, all I need to do is to change this line to

@part = Part.new(:category => params[:category], :size => params[:size])

And like that, the form_tag works exactly the same as the form_for in the case of the new method. However, if we want to use the edit method, we're not quite done. Normally, with edit, the values will already be filled in with whatever values they already have. And update uses the put command, while create uses the post. So we have to change that as well. Here's how the new and edit views will look:

New

<%= form_tag create_part_path, :method => :post do %>
  <%= render 'form' %>
<% end %>

Edit

<%= form_tag update_part_path, :method => :put do %>
  <%= render 'form' %>
<% end %>

Form

<%= text_field_tag :category, @part.category %>
<%= text_field_tag :size, @part.size %>
<%= submit_tag %>

That will take care of filling in values where they've already been set.

Now, if this were all I wanted to do, I'd stick with the form_for because it's simpler. However, in this particular case, I want the form to do a bit more. I have another table called tiles, which is a very simple table. It just has a field for a name and a field for a part_id. We basically have three different types of tiles. And a part has to be for at least one tile, but it can be more more than one tile. So a part has_many tiles and a tile belongs_to a part. In the form, I want to have checkboxes showing the three tiles so that the user can check which tile this part is used in. Since this means I'll be sending an array of some sort about the tiles, I no longer have a one-to-one relationship between the form and the part table. So I really can't use the form_for method and have to use form_tag to create my form. Then in the create method, I will do whatever is necessary to create the part and tile entries. The other issue is that there's a little bit of difference between the create and update methods. My solution to this was to still use a _form partial, but to put the form_tag line in the new view (which will call create_part_path) and the form_tag that calls update_part_path in the edit view.

So, to add our checkboxes of tiles, we need to change our new, edit, create and update methods like this:

def new
    @part = Part.new
    @parts = Part.all
    @tiles = Tile::NAMES
    @part_tiles = []
  end

  def edit
    @part = Part.find(params[:id])
    @tiles = Tile::NAMES
    @part_tiles = Tile.where(:part_id => @part.id).order(:name).pluck(:name)
  end

def create
    @part = Part.new(:category => params[:category], :size => params[:size])
    @tiles = params[:tiles] ||= []

    if @part.save
      @tiles.each do |tile|
        Tile.create(:name => tile, :part_id => @part.id)
      end
      redirect_to root_url, notice: 'Part was successfully created.'
    else
      render action: "new"
    end
  end

def update
    @part = Part.find(params[:id])
    @tiles = params[:tiles] ||= []

    if @part.update_attributes(:category => params[:category], :size => params[:size])
      @tiles.each do |tile|
        t = Tile.find_or_initialize_by_name_and_part_id(tile, @part.id)
        t.update_attributes(:name => tile, :part_id => @part.id)
      end
      redirect_to root_url, notice: 'Part was successfully updated.'
    else
      render action: "edit"
    end
  end

Tile::NAMES is just an array in the model I use with the names of the three tiles. This should not change, so a hardcoded array is fine. In edit, the @part_tiles is just an array of tile names that have been set for that particular tile. If none of the checkboxes are checked, it should just be an empty array. We'll need this to precheck the boxes in the edit form.

The final version of the form looks something like this:

  <%= text_field_tag :category, @part.category %>
  <%= text_field_tag :size, @part.size %>
  <% @tiles.each do |tile| %>
    <%= check_box_tag "tiles[]", tile, @part_tiles.include?(tile) %>
    <%= tile %>
  <% end %>
  <%= submit_tag %>

That's it. At the end of the form, we loop through our list of tiles and make a checkbox next to each one. If the name of the tile is included in the array @part_tiles, then we know it's already been set and should default to checked.

Sendmail on Mac OS X 10.8

I wanted to use sendmail to test the sending of some messages in one of my apps. The command I wanted to run was:

yo:~ $ sendmail -t < y

I got this error:

yo:~ $ sendmail -t < y
sendmail: fatal: chdir /Library/Server/Mail/Data/spool: No such file or directory

Fixed with:

yo:~ $ sudo mkdir -p /Library/Server/Mail/Data/spool
Password:
yo:~ $ sudo /usr/sbin/postfix set-permissions
chown: /usr/share/man/man1/postalias.1.gz: No such file or directory
yo:~ $ sudo /usr/sbin/postfix start
postfix/postfix-script: warning: group or other writable: /Library/Server/Mail/Data/mta
postfix/postfix-script: starting the Postfix mail system 

Now the sendmail -t command works as expected.

Contents of the file y:

yo:~ $ more y
To:  [email protected]
Subject: Thanks!
Content-Type: text/plain; charset='UTF-8'

Dear Me,

Thank you for doing whatever it is that I'm thanking you for.  It's been a pleasure.

Sincerely,
Me

Ruby File Open Options

I spent a little time looking for this info, so I thought I'd post it here. Use it like this:

File.open("#{output}","a") do |w|
  w << "#{Time.now.to_s(:datetime_stamp)} Other text to write
end

Remember if you use File.open or CSV.open with a block, the file is automatically closed when the block closes. Otherwise you have to close the file.

  Mode |  Meaning
  -----+--------------------------------------------------------
  "r"  |  Read-only, starts at beginning of file  (default mode).
  -----+--------------------------------------------------------
  "r+" |  Read-write, starts at beginning of file.
  -----+--------------------------------------------------------
  "w"  |  Write-only, truncates existing file
       |  to zero length or creates a new file for writing.
  -----+--------------------------------------------------------
  "w+" |  Read-write, truncates existing file to zero length
       |  or creates a new file for reading and writing.
  -----+--------------------------------------------------------
  "a"  |  Write-only, starts at end of file if file exists,
       |  otherwise creates a new file for writing.
  -----+--------------------------------------------------------
  "a+" |  Read-write, starts at end of file if file exists,
       |  otherwise creates a new file for reading and
       |  writing.
  -----+--------------------------------------------------------
   "b" |  Binary file mode (may appear with
       |  any of the key letters listed above).
       |  Suppresses EOL <-> CRLF conversion on Windows. And
       |  sets external encoding to ASCII-8BIT unless explicitly
       |  specified.
  -----+--------------------------------------------------------
   "t" |  Text file mode (may appear with
       |  any of the key letters listed above except "b").

Simple Dropdown Menu of Numbers

Every so often I need to make a simple dropdown menu of numbers in my app. And for some strange reason, I always seem to forget how to do this. So here are some examples for myself to use when I forget the next time.

1. I need to let students pick the grade their in. In this example, we are only allowing students in grades 6-8. So I used this:

<%= f.select :grade, options_for_select([6,7,8]) %>

Looks like this:

2. I need to find out how many parking vouchers someone will need. I want the 0 option to say, "No Parking Vouchers Needed".

<%= f.select :parking, options_for_select(([["No Parking Vouchers Needed",0],[1,1],[2,2],[3,3]]), :selected => @attendee.parking ) %>

Looks like this:

3. The only roles for users are either user or admin. In the model, I have this:

ROLES = %w[user admin]
def role_symbols
  [role.to_sym]
end

Then to make a dropdown menu of these choices, I use:

<%= f.collection_select :role, User::ROLES, :to_s, :humanize %>

Note that when using a form_tag, there is no corresponding collection_select_tag. Instead, you need to do this:

<%= select_tag :status, options_from_collection_for_select(Part::STATUS, :to_s, :titleize) %>

Looks like this:

4. I have a table of workshops that people can attend. To make a dropdown list of the workshops in the table, I use:

<%= f.collection_select :workshop_id, Workshop.by_title, :id, :title, { :include_blank => true } %>

Looks like this: