Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts

Thursday, October 8, 2015

(Sadly) I am so done with this...

Years ago when I first started working with Ruby on Rails (back in the version 1.0 days) I started off on a Windoze machine... and we all know what a major headache that was. It didn't take me too long to start looking for other alternatives and I settled eventually on Kubuntu.

It took a lot of work to get things up and running but I slowly learned more and more about bash, and setting up Apache, and getting Samba to work on my mostly Windoze network. A lot of work but I eventually got things working and was able to happily develop my system on that platform. I really came to love the power and flexibility that was possible on Linux.

Eventually, I started working with some older MacBooks and while they were relatively under-powered and had their quirks it was a pretty nice setup. And for the past two years now I've been working with current MacBooks and loving it. However, when starting up a new project, I decided to got back and see how Linux would work: it would be my desktop / base machine and I could still use the MacBook when I was on the road.

As usual, there were a number of glitches, not the least of which was that my last version was 12.10 and was no longer supported. Not only does Ubuntu not support the old releases, they actually take down any servers that contain the files necessary for an upgrade so you're pretty much out of luck. I didn't want to start from scratch as I had a lot of things configured. I already had my /home on a separate hard drive so I was eventually able to migrate things over and get up and running on 14.04.

I figured I was good to go... wrong.

Running Rails 4.0 turned out to be a problem: capybara-webkit refused to install so I started researching that. More hassles, more delays, but I figured it would settle down soon.

Wrong again.

I decided to do a reboot and that's when things got really, really bad. I got dropped into a grub rescue prompt, with complaints about a parameter that some well-meaning application had added. And even setting the boot drive (after even more research) didn't solve the problem.

Fortunately I don't have much on the system that isn't backed up -- there's only one small system and database that I'll need to recover but this time I'm going to do it with a live disk and then...

...I am done with Linux. I've come to the opinion that Linux is really great for two kinds of people:
  1. People that want to learn and play and don't mind re-installing frequently.
  2. People that really really know how to make this stuff work well -- sysadmins.
Unfortunately I'm not one of those two kinds: I want to use the system to get meaningful work done, I don't have time to learn everything, and I certainly don't qualify as a sysadmin, even though I've gotten lots of things working over the years.

So... sayonara, Linux... it's been good to know you. You've been a good companion -- albeit often a frustrating one -- and I've learned a lot from you, but it's time for me to move on.

Tuesday, December 23, 2014

Trust your auto indentation... really

I knew I liked my editor's autoindent feature, but I didn't realize how valuable it was until this situation popped up. I was reading the book Rebuilding Rails (worth a look) and happened to code a simple method as part of one example.
def call(env)
  (klass, act) = get_controller_and_action(env)
       controller = klass.new(env)
       text = controller.send(act)
  [200, {"Content-Type" => "text/html"},
...
As you can see the indentation isn't correct for the 'controller =' and 'text =' lines and try as I might
vim gg=G
it wouldn't indent properly.  I chalked it up as low priority weirdness to be dealt with later until I loaded up the program and got this error:

undefined local variable or method `controller' for ...

I finally dropped into HexDump mode using vim's nifty little xxd utility
:%!xxd
and got this output for the lines that wouldn't indent properly.
0000060: 6c28 656e 7629 0a20 2020 2020 2028 6b6c  l(env).      (kl
0000070: 6173 732c 2061 6374 2920 3d20 6765 745f  ass, act) = get_
0000080: 636f 6e74 726f 6c6c 6572 5f61 6e64 5f61  controller_and_a
0000090: 6374 696f 6e28 656e 7629 0a20 2020 2020  ction(env).    
00000a0: 20c2 a0c2 a0c2 a0c2 a0c2 a063 6f6e 7472   ..........contr
00000b0: 6f6c 6c65 7220 3d20 6b6c 6173 732e 6e65  oller = klass.ne
00000c0: 7728 656e 7629 0a20 2020 2020 20c2 a0c2  w(env).      ...
00000d0: a0c2 a0c2 a0c2 a074 6578 7420 3d20 636f  .......text = co
00000e0: 6e74 726f 6c6c 6572 2e73 656e 6428 6163  ntroller.send(ac
Notice the 'c2a0' sequence repeated five times in front of the 'controller =' and 'text =' lines. Those non-printing characters were the culprit: the actual variable name was 0x'c2a0c2a0c2a0c2a0c2a0'controller, for example so when I tried to use 'controller', that was still undefined. How those byte pairs got inserted remains a mystery. But I am guessing from this post that it was a non-breaking Unicode character.

Saturday, September 25, 2010

Custom Form Builders in Rails...

I've started working on a new Rails application and needed to display chunks of spreadsheet-like text for financial data (e.g., Profit & Loss Statement and Balance Sheet). Everything went fine (well, not so fine: money fields were a bit of challenge, but more about that later) until I started displaying my data in a view. As you can imagine, there are a lot of cells for these displays and after some prototyping, I realized that the default size of 30 for an input field was just too big. Of course, that's easy to solve by just adding ":size => 15" to the text_field definition, but the prospect of adding that to numerous fields and than probably having to change them all left me pretty grumpy.  That's when I figured that a Custom Form Builder would be the way to go.

As usual, I headed off to the Rails API but found little there and much of the external documentation on how to use them was either way over-complicated for what I wanted to do, or going in another direction.  I did find a few good resources, including the following:

1. Ryan Bates' "Mastering Rails Forms" episode 3 - Great presentation; worth every penny of the $5 cost per episode.
2. APIDoc description of form_for method - APIDoc is your very good friend.
3. Alex Reisner's "Anatomy of a Form Builder" - Best introduction of the details behind Form Builder I found.
4. Ruby Pond's Semantic Form Builder - Lots of complex changes, nicely done
5. Aldenta post with metaprogramming example - Shows how to replace a slew of methods with metaprogramming; compare to Ruby Pond example where they are all hand-crafted.

Because of their often complicated solutions and the fact that there were different ways of doing things, I found it challenging to extract the minimum that I would have to do make a simple change. In the end, after much reading and trial coding, Ryan Bates' "Mastering Rails Forms, episode 3" completed my current understanding of the process.

Here are the key points that I learned which finally helped me get through the morass and make it work for me. In the discussion that follows, CustomFormBuilder is my class name.

To start, this is the code that I wanted to change...
from this:
<td>f.textfield :name, :size => 12</td>
to this:
f.textfield :name
Not a big change at all, but with many lines like this, I thought this would be a nice, easy way to learn about custom form builders.

Here's what I learned that helped me understand how it all works.

1) the basic form builder code looks like this:
class CustomFormBuilder < ActionView::Helpers::FormBuilder
 ...your code...
end
There may be other approaches out there that will work, but this is the most straight-forward way I have found.

You want to be able to reference your custom form builder easily, as in:
form_for :person, :builder => CustomFormBuilder do |f|
...form code...
end
It turns out there are ways to customize even this, so that your code looks like this:
custom_form_for :person do |f|
...form code which automatically uses your CustomFormBuilder
end
but that's for a little further down the page.

2) There is more than one way to implement the logistics of a custom form builder (reminds me of Perl's TMTOWTDI and I am rapidly coming to the conclusion that this applies to Rails everywhere). This was one of the things that tripped me up at first, since different posts give different instructions on how to create your builder. By logistics I mean where do you put the code that will be your form builder so that you can reference it easily?
  1. You can put it in a helper file... either in application_helper.rb or controller_helper.rb. The basic code layout is as described above... The really important thing about including this code in an existing helper file is that the code MUST come after the end statement that terminates the helper code! Failing to do this will result in your form builder not being found (this one cost me a few hours) or your having to reference it as:
    :builder => ApplicationHelper::CustomFormBuilder
  2. You can put it in a separate file in the helpers directory, with a name that matches the class name, i.e., custom_form_builder.rb
  3. You can put it anywhere you like (for example, like Ryan Bates does, in a separate directory that you create called app/form_builders). In this case, however, you must add that directory to Rails' default search path by adding the following to your environment.rb file (just uncomment and modify the skeleton statements that's already there):
    config.load_paths += %W( #{RAILS_ROOT}/app/form_builders)
3) You can make your CustomFormBuilder the default by adding the following to the bottom of your environment.rb file. Doing this means that you can leave off the :builder => option in your form_for:
ActionView::Base.default_form_builder = CustomFormBuilder
  • However, I think I agree with Ryan Bates that this is not such a great idea -- it hides what's going on and could make it difficult for some one new to your code to figure it out.
  • [Note]: Other authors recommend doing this in app/helpers/application_helper.rb and one author explicitly stated that the environment.rb approach would not work because helpers don't get initialized until they are actually called/used {could this be a version-dependent issue?]
4) Altlernatively, you can make a helper method that encapsulates the CustomFormBuilder and makes it explicit that you've got some extra magic going on. Do this in your Application Helper file:
def custom_form_for(*args, &block)
  options = args.extract_options!
  options.merge!(:builder => CustomFormBuilder)
  form_for(*(args + [options]), &block)
end
5) The code to actually do this very simple change is also very simple:
def text_field(name, options = {})
  options.reverse_merge! (:size => 12)
  @template.content_tag(:td, super)
end
  • The "reverse_merge" is so that I can override the default size of 12 with another value coded in the form
6) You'll see in some of the examples that the method signature is given with *args instead of option as I have shown it. That's a more general approach, but requires that you know a little more about how Rails can manipulate the arguments; see below. Suffice it to say that it works for my simple example, but if you're going to get serious about making more complicated customm form builders, you should get familiar with the following approaches.

extract_options! is a Rails method that will -- not surprisingly -- pull the options hash out of the method arguments. Very useful for the general method signature which uses *args.

merge! and reverse_merge! are methods that will merge and overwrite the receiving hash with the results. So, for example:
options.merge!(:size => 12)
will add :size => 12 to the options hash, while:
options.reverse_merge!(:size => 12)
will add :size => 12 to the options hash ONLY if there is no :size element already there.
  • Note the bang (!) on each of these methods -- very important. If you use the non-bang version, you won't update the options hash and things just won't work.

content_tag is a method on the @template object (provided to you by the FormBuilder) that wraps selected text in the given HTML tag. Very useful for building your output string.

There's lots more, but that should be enough to get you started -- hopefully a little easier than I did. Now that I understand some of these basics, looking at the more complicated examples is much easier for me.

Tuesday, August 24, 2010

Firing up a new Kubuntu machine for Rails development...

Well... it finally happened.

My Kubuntu machine which I prefer to use for Rails development was getting pretty crochety. I had started out on 7.04, did a distribution upgrade to 8.04, ran into some major problems installing DropBox (LinuxFormat Magazine helped me fix this problem). Finally, I tried a distribution upgrade to 9.10 and it was barely limping along. Several folks suggested a clean install from scratch, so I decided to go with Kubuntu, 10.04, 64-bit.  Here's how I went about it.

Prior to the installation, I took a tar backup of my system and also did a copy (cp -a ...) to an external USB drive. Be careful with cp: if you have other media attached (like another network-attached drive I had a /media/wdhd1), the command "cp -a / /" will follow all those links and try to get EVERYTHING onto the USB drive. I wound up simply copying over the directories that I was most interested in gaining quick access to, such as: /home, /etc, /root, /rails-app. If you've got an old system that you're going to replace, pick the directories that you don't want to lose.

BTW, I really like the NDAS combo drives: eSata, Network-Direct Attached, USB. Reasonably-priced and very effective.
  1. First get Kubuntu (or whatever flavor of Linux distro you want). I went to the Kubuntu site at http://www.kubuntu.org/getkubuntu where you can either download directly or get a CD/DVD. I downloaded the 64-bit desktop version here: http://www.kubuntu.org/getkubuntu/download#download-block
  2. Install kubuntu - pretty straight-forward.
    1. Make sure that your machine will boot from a CD
    2. Insert CD, reboot, follow the instructions.
    3. A true linux sysadmin might have gotten fancy with the disk partitioning, but I just went with the default which was everything in a single partition. It’s not like this is a heavily-loaded server...right?
    4. There were a number of prompts for keeping or replacing existing files (such as mysql/mycnt, /etc/apcupsd/apcupsd.conf, /etc/cups/cupsd.conf, etc...) and I just took the default since I had copies of all my previous config files.
    5. At one point, my mouse went inactive (I connect it through a KVM switch) but that cleared up pretty quickly.
  3. Install your favorite browser by using Kubuntu’s built-in Konqueror browser. I chose Chrome -- I’ve been using Firefox for years, but in the past, I’ve run into problems with Firefox on Linux: older versions, conflicts when trying to upgrade... I still use FireFox on Windows/Mac, but Chrome is my preferred browser for Linux.
  4. The Ubuntu community has a very good site on how to do the Rails install: https://help.ubuntu.com/community/RubyOnRails
    1. Make sure you DO NOT do “sudo apt-get install rails”. This gives you an old version and you can’t track your gems easily. If you mistakenly do that, simply type “sudo apt-get remove rails” and go back to the above link
    2. REMEMBER to add the new ruby gems path to your path so that your system can find the stuff you just installed (this is in the . The command is:
               “
      export PATH=/var/lib/gems/1.8/bin:$PATH”
      You’ll have to add this to your .bashrc file so that it will always be done when you start up.
      1. BTW, I add the following two aliases to my .bashrc so that I can quickly and easily edit .bashrc and update my environment for any new values
        1. alias brcs='source /home/jseidel/.bashrc'
        2. alias brcvi='vi /home/jseidel/.bashrc'
      2. The ‘brcvi’ alias drops me into vi (replace with your preferred editor) so that I can make changes. Notice that it always points to my home directory so that I can do this regardless of where I am.
      3. the ‘brcs’ alias “sources” the current/updated .bashrc file. I.e., it “Reads  and  executes  commands  from .bashrc in the current shell environment”, with the result that the changes you made are reflected in your current bash environment. So to add a new alias, I create the alias in my current bash, test it out, then brcvi to add it to my .bashrc and then brcs to make it active and then test to make sure I didn’ have a typo.
  5. Install git -- you are using git, aren’t you? GitHub has a great tutorial on how to do this. Just go to: http://help.github.com/linux-git-installation/ and follow the instructions. There's also an excellent book, Pro Git, by Scott Chacon, that is available on line at http://progit.org/book/.
  6. Once you’ve installed git, you have to generate an SSH keypair (see http://en.wikipedia.org/wiki/Secure_Shell if you want to learn more about SSH and http://en.wikipedia.org/wiki/Public-key_cryptography if you want to learn more about keypairs) so that you can speak encrypted git.  GitHub has another excellent tutorial on how to do this; see http://help.github.com/linux-key-setup/. Just follow the instructions there and you should have no problem. I did install the xclip utility -- makes it easy to copy/paste the information into github.
    1. If you don’t want to key-in your SSH passphrase everytime you use it, GitHub has help here as well. Go to http://help.github.com/working-with-key-passphrases/ and about half-way down the page there’s a section on “autolaunching ssh-agent” when you start your machine so that you only have to enter the passphrase once when you boot your machine.
    2. Turns out I had some permissions problem in my .ssh directory: I kept getting
            “Bad owner or permissions on /home/jseidel/.ssh/config”
      when testing things with “ssh git@github.com”.  Well, GitHub was there again, with their trouble-shooting page at
      http://help.github.com/troubleshooting-ssh/. Towards the bottom of the page in the “SSH Config” section, the two ‘chmod’ commands did the trick for me.
       
         chmod 700 ~/.ssh chmod 600 ~/.ssh/*
    3. And don’t forget to setup your git config options -- at least these two
         
      git config --global user.name "your name"
         git config --global user.email your@email.com
  7. I use RubyMine (http://www.jetbrains.com/ruby/download/index.html#linux for a 30-day free trial) so that was the next thing to install. Replace this section with whatever IDE you prefer: Aptana, NetBeans, ...  
    1. To run RubyMine, you have to have the Sun Java (JDK 1.6). I found that at http://www.oracle.com/technetwork/java/javase/downloads/index.html and followed the instructions. It turned out to be completely straight-forward.
  8. Now you’ve got everything ready to do; let’s create your first rails app in your shiny new Linux development machine:
        
    rails MyApp
        
    cd MyApp
        
    git init
        
    git commit -m "Empty Rails application"
  9. Now create your github repository -- GitHub has the answer again: http://help.github.com/creating-a-repo/
    1. Once this is done, copy in the repository URL
  10. Back to bash and hooking up your new repository with your new rails app
    1. Tell your local git repository about the github repository:
          
      git branch add origin
    2. Push your MyApp rails application up to github:
          
      git push origin master
And you should be good-to-go -- happy rails to you!

Tuesday, April 27, 2010

Authlogic login error messages...

I've been using autthlogic to provide login/signup features for my new web application, and I really like it. It provides lots of great features and has a fair number of plugins and tutorials to add functionality.

A few weeks past, I added a password reset feature. This was quite straight-forward: I just followed the password-reset tutorial and was up & running pretty quickly.

However, when I did some additional testing on the basic authlogic functionality, I noticed that it took a very simplistic approach to providing error messages for login failures: it would report "Invalid email address" or "Invalid password" if either of those fields were in error. This is not good security: an attacker could determine a valid email address and then use it for social engineering to gain further information.

Support to fix this is already in Authlogic -- it's just not the default behavior. You have to add the following method call to your UserSession class:

     class UserSession < Authlogic::Session::Base

       generalize_credentials_error_messages true

     end

More details can be found at: http://railsapi.com/doc/authlogic-v2.1.3/classes/Authlogic/Session/Password/Config.html#M000178

This post is mostly about collecting the various sources of information about Authlogic -- it's such a popular Rails plugin, that there are many search results, some of them dead or not very helpful. I spent almost an hour googling to find the right stuff, and figured I'd post what I found in case it might save someone else some time.

General github/authlogic documentation page: http://rdoc.info/projects/binarylogic/authlogic. The "documentation" link sends you to an RDoc Info page: the main page is an overview, and you get more detail by clicking on the 3 buttons in the upper right-hand corner: "Namespace list", "Method list", and "File list".

More documentation can also be found at: http://railsapi.com/doc/authlogic-v2.1.3/ .

All in all, really good stuff!

Monday, March 22, 2010

MacPorts headaches... solved!

So I finally found a way to solve all those MacPorts headaches, thanks to Erik Michaels-Ober, a friend of a friend. As I and many folks have learned, Mac OS X is less than standard *Nix when it comes to setting up their directories, and it doesn't take kindly to co-creation of a parallel directory tree. MacPorts puts things in the (*Nix) standard /opt directory, but once that's done, you get path and name clashes.

I've seen bits and pieces of a solution as noted in my previous posts, but they really didn't fix the problem. And of course, there's the issue that's been reported elsewhere that upgrading to Snow Leopard can wreak havoc on a development setup.

So following Eriks' instructions, here's what I did:
  1. I wiped my system clean and installed Snow Leopard from scratch. You may be able to just do an upgrade, but I chose to go with a clean system.
  2. Install the XCode Developer Tools that come with Snow Leopard (or download the latest version from the Apple website. Warning: it’s a big file).
  3. Remove all the pre-installed rubygems from your system. You can do this using the “gem uninstall” command, or brute force. I chose the brute force method, but only after creating a copy before I did the deletion, just in case. Once I knew it worked, I got rid of my copies.
    rm -rf /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/*

    rm -rf /Library/Ruby/Gems/1.8/*
  4. Install MacPorts (see the MacPorts installation page).
  5. Make sure you’re running MacPorts version 1.8.2 (type: port version). If not, run the command:
    sudo port selfupdate
  6. Install the MacPorts version of ruby itself:
    sudo port install ruby
  7. Install the MacPorts version of rubygems:
    sudo port install rb-rubygems
  8. Install the MacPorts version of git:
    sudo port install git-core
  9. Upgrade to the latest version of rubygems:
    sudo gem update --system
  10. Make sure you’re running rubygems version 1.3.5 (type: gem -v). If not, run the command: update_rubygems
  11. Install all the gems you want (rails, heroku, etc.). They will be installed into /opt/local/lib/ruby/gems/
I set up my machine about a month ago and it's been working fine ever since.

Enjoy...

Monday, August 17, 2009

Interesting svn "gotcha"...

I just learned that you have to be careful about which version of subversion you are using if you have an IDE and also want to use the command-line client.

Starting about V1.4, there were changes in the internal structure of the subversion directory hierarchy (i.e., the .svn files that it creates to track things) which means that you have to make sure that your versions are in synch.

For example, I'm using Aptana Studio, which is eclipse-based, and which uses the latest subclipse client (subversion for Eclipse). That latest version is V1.6. However, on my Kubuntu development box (V8.04/Hardy Heron), the latest subversion package right now is V1.4. If I try to run a subversion command from the shell, I get this error message:
jseidel@EDP15:~/AptanaStudio/4MyPasswords$ svn status
svn: This client is too old to work with working copy '.'. You need
to get a newer Subversion client, or to downgrade this working copy.
See http://subversion.tigris.org/faq.html#working-copy-format-change
for details.

The help link above will explain that -- due to new features in the later versions -- they had to introduce new structure which is incompatible with the older clients.

Since I don't want to downgrade my working copy, I went looking for V1.6 command-line clients. Sad to say, they aren't packaged (yet) for Kubuntu/Hardy --so far I only found it for the Karmic version of Ubuntu.

There are other svn clients out there, either as wrappers around the command line client, or full-on clients. One that I looked at was kdesvn. This looked to be a nice client and was at V1.6. Unfortunately, the developer only provides a Fedora package, so I would have to build my own from source.

I went to the subversion site, but the referenced Ubuntu binaries only pointed back to the Ubuntu site and the older version, so I tried building it from source. Bad move! As stated on their site, there are a number of dependencies which I started to work through one at a time. When I reached a point of having to figure this out:
jseidel@EDP15:~/downloads/subversion-1.6.4/subversion-1.6.4$ apr/buildconf
buildcheck: checking installation...

buildcheck: autoconf version 2.61 (ok)

buildcheck: autoheader version 2.61 (ok)

buildcheck: libtool version 1.5.26 (ok)

buildcheck: local copy of find_apr.m4 does not match APR's copy.

An updated copy of find_apr.m4 may need to be checked in.
buildcheck: local copy of PrintPath does not match APR's copy.

An updated copy of PrintPath may need to be checked in.
Copying libtool helper files ...

buildconf: Using libtool.m4 at /usr/share/aclocal/libtool.m4.

Creating include/arch/unix/apr_private.h.in ...

Creating configure ...

configure.ac:185: error: possibly undefined macro: AC_PROG_LIBTOOL

If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
Generating 'make' outputs ...

apr/buildconf: 91: build/gen-build.py: not found rebuilding rpm spec file

apr/buildconf: 107: build/get-version.sh: not found

cat: ./build/rpm/apr.spec.in: No such file or directory


I quit trying: I want to work on my application, not have to learn THIS much about the internals of the tool I want to use... Argh! For now, I'm sticking with the Aptana support which is working (with some help from the Aptana support folks), although I do miss the ability to do quick svn commands from the shell.

I think Linux needs to come up with a better installation mechanism...