For those of you in the Columbus area, I’ll be speaking at the Columbus Ruby Brigade meeting this evening regarding Rails 2.0. This will be a high-level talk around some of the new things and some of the deprecated behaviours in everyone’s favorite web framework.
validates_acceptance_of howto 1
We’re really getting things rolling on Gonowdo and as part of that, we’re starting to accept users on a somewhat limited basis. When signing up, I need to make sure that users accept our terms of service. With Rails, this is extremely simple, but after spending a few minutes on mailing list archives and forums I didn’t find a good resource or howto. Hopefully, this post will serve as that for anyone in the future.
The key to accomplishing this is to use an active record validation called “validates_acceptance_of”. Adding this to the User model with a method will create a virtual attribute for that named method, in my case, I used “terms_of_service”. There is no corresponding column in the database needed. This will not allow a model to be saved without it. By default, this method will allow the record to be saved if it is nil. Setting it to true will mean that you must pass this value to the record everytime you want to save it. One other thing, in order be able to access this method from the view, you need to make it accessible by creating an accessor. Here is the example from our application.
1 2 3 4 5 6 7 8 |
class User < ActiveRecord::Base # ... validates_acceptance_of :terms_of_service # ... attr_accessible :terms_of_service end |
In the view, you just need to add a control to the form for selecting this checkbox. Without checking this box, the form will throw a validation error and the model will not be saved.
1 2 3 4 5 6 |
<% form_for :user, @user, :url => users_path do |f| %> <p>... other controls ...</p> <p><%= f.check_box :terms_of_service %> I accept the terms of service.</p> <p><%= submit_tag "Save" %></p> <% end %> |
There are several other configurations that you can pass to validates_acceptance_of, similar to other validations. Check the documentation for this method for more information. If you have more stringent auditing requirements, then you may need to think about just using a boolean field in the database and using a regular validation. Extending this further might even allow you to track acceptance of versions of your terms of service as they get updated. Since we’re allowing nil by default, you will need to make sure that create a test/spec to specifically pass a :terms_of_service method. I would keep this in a special test case and not worry about including it throughout your test suite.
Hopefully, this will get you going, best of luck!
RSpec NO NAME error
A New User -- NO NAME (Because of --dry-run) -- NO NAME (Because of --dry-run) -- NO NAME (Because of --dry-run)I was able to determine that the rake task does indeed call dry run. Here’s the task,
1 2 3 4 5 6 |
desc "Print Specdoc for all specs (excluding plugin specs)" Spec::Rake::SpecTask.new(:doc) do |t| t.spec_opts = ["--format", "specdoc", "--dry-run"] t.spec_files = FileList['spec/**/*_spec.rb'] end |
./script/spec spec -fsI’m not sure that I understand why this is the expected behavior because I give the test a name, so I’m not expecting it to be run. If anyone has an explanation, I would greatly appreciate it.
Nginx iz teh 1337 h4x0r
I spent the evening migrating this mephisto installation from apache to nginx. It was quite easy to install and configure. I’ve also cut down my memory by a few MBs. I’m having a little problem with some of the virtual hosts, but I think it’s an issue with my DNS, not necessarily the configs. My initial impression is that my pages are loading in the 1/2 the time. I’m too tired to post more, I’ll try to get to it tomorrow, including statistics, but if you have a choice, you should be using nginx, NOW.
Prototyping with Camping 2
As you might know, I’ve been spending a lot of time at work writing some dashboard-type applications using _whytheluckystiff’s Camping Framework. I’ve been experiencing some incredible productivity gains by prototyping with this very small framework, and I think I’m only just beginning to realize exactly how much. I’ve recently undertaken rewriting one of these dashboards in Rails.
The Camping Application
Several months ago, I was tasked with providing some statistics on budget and project management performance for senior management. The maturity of datasources wasn’t very good, many of them were excel spreadsheet laden with macros, access databases, and csv files from 5 or 6 datasources. To further compound the problem, these datasources weren’t always in a consistent data format, so I made the design decision to just create a simple CRUD interface to manually enter the data. All compilation would be handled outside the application for the time being. The benefit of this approach would be that eventually, I could turn the data entry over to someone else.
I developed this solution over the course of about 2 weeks, working on and off until there was a format visually appealing to all parties. I wrote the most basic tests possible using Topfunky’s Mosquito Testing Framework. This solution worked until the application needed to be expanded to the entire organization, not just a subset. It was time to move to Rails.
The Rails Application
In addition to changing the domain to fit the entire organziation, I really wanted to have an extremely clean interface for someone else to enter the data. My goal was to have someone else take over entering the data, and I would just be responsible for the support of the application. Rails also gave me an opportunity to more easily explore automating some of the data entry.
In 2 days, working on it for 8 hours a day, I’m 90% complete, including adding the additional models and unit and functional tests. I realize that it’s a small Rails application, but now if there are enhancement that need to be made I’m on a much better platform.
+----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 560 | 395 | 8 | 49 | 6 | 6 | | Helpers | 20 | 19 | 0 | 1 | 0 | 17 | | Models | 152 | 130 | 7 | 18 | 2 | 5 | | Libraries | 14 | 11 | 0 | 3 | 0 | 1 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 434 | 342 | 14 | 63 | 4 | 3 | | Unit tests | 745 | 565 | 8 | 154 | 19 | 1 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 1925 | 1462 | 37 | 288 | 7 | 3 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 555 Test LOC: 907 Code to Test Ratio: 1:1.6
So in proper enterprise +3/-3 format, here are some observations…
Eagles
- My models are almost an exact copy from Camping, with more validations and a couple of additional models that I needed to add for the extra functionality.
- I already knew the domain of what I needed to create so any reworking could be accomplished on the first pass with Rails.
- I already had lots of good data to use for Rails development as I just pulled fixtures down from the Camping app.
Turkeys
- I miss clean view syntax of Markaby in Rails. I realize that I could use Markaby, but if support for this application eventually gets turned over to another group, I thought that the barrier to entry would be lower for the JSP-style syntax of ERB templates.
- I had to manually copy and paste a lot of code from one Emacs screen to another. There was rumored to be a gem that would transistion a Camping application to Rails, DeCamper, but I couldn’t find any code that had been released. This bears further research.
- Rails migrations and Camping migrations aren’t very similar, and I wanted to have the cleanest Rails application possible. I reworked the models enough that it just didn’t transfer very well.
Summary
I’ve been in too many situations where I work on things for too long only to have the organziation go in a different direction. Using Camping to prototype before moving on to Rails gets something for my users to react to before I’m too invested in the outcome of my work. When, and if I do need to move to Rails, the transition is seemless and probably cuts down on the total time to get a finished product into production. I’ve been very pleased with this approach, but I think I can reduce the turn around time even further. I think some possible options would be to use ERB with Camping or Markaby with Rails. Also, I think I should have perhaps gone to Rails a few weeks ago, but time was just too hard to come by. The next time you come across a situation that warrants creating something of immediate use that may or may not be thrown away after an initial pass, you should think about this approach.
Rails Trademark Madness 1
So, it would appear that the Rails trademark discussion isn’t quite over. On the 27th of July, Dr. Nic Williams registered a trademark for:
- Educational publications, namely, training manuals in the field of information technology
- Dissemination of advertising, scheduling and managing of training courses and programs for others via a global computer
- Arranging professional workshop and training courses
This is in addition to the one originally filed by David Heinemeier Hansson about the usage of Ruby on Rails in Computer software, namely, software framework for developing web applications. Apparently, that one isn’t completely through the door, yet.
What does all this mean? 1) Patent and trademark law seems completely jacked up in the US. 2) It means that the name of a thing is valuable, not the thing itself.
For those of you thinking about filing a trademark on your service, let me ask a question. Are you a great Rails developer, or are you a great developer who uses Rails?
My First Patch 2
I am no longer an innocent bystander to the world of open source projects. I’ve had my very first patch applied to a code base. While working on a tiny Rails project, I used Rick Olsen’s restful_authentication plugin/generator. The tests failed immediately due a change in the api for assert_difference. I made the changes, and submitted a patch to Rick, and he applied it last night, along with a couple of other small changes.
I’ve been wanting to start getting involved with more patching, but just haven’t had the opportunity. I even set-up a specific workspace on my laptop just for things that I’m going to be patching, that way I can keep it separate from my own projects.
How exciting!
Emacs Railsy-ness
For the most part, I followed the instructions at Dima’s Rails On Emacs page. This worked for the most part, however there were several gotchas that crept up as I was working my way through. Here’s what I did, that might be different than the other tutorials:
- I placed the snippets.el and find-recursive.el into the folder that I checked out the Rails on Emacs code. (Perhaps this is what he meant by install, but I originally had them in .emacs.d, and that was wrong.) ruby-inf.el did, however remain in .emacs.d
- I reinstalled ruby and installed ruby-elisp from synaptic. I did this because I read that when you install ruby on debian/ubuntu it will automatically install the necessary emacs modes.
- Tip After opening emacs, change your buffer to “Messages” it will have all the init information, and I found it very handy for debugging.
I’m also going to install the Emacs Code Browser, which is supposed to provide some parsing of files to show methods, and other view-related functions.
Here’s my .emacs file:(custom-set-variables ;; custom-set-variables was added by Custom -- don't edit or cut/paste it! ;; Your init file should contain only one such instance. '(standard-indent 2)) (custom-set-faces ;; custom-set-faces was added by Custom -- don't edit or cut/paste it! ;; Your init file should contain only one such instance. '(default ((t (:stipple nil :background "#000000" :foreground "#00ff00" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 164 :width normal :family "adobe-courier"))))) ;; this line makes a file executable after saving it ;; (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) (setq load-path (cons "~/.emacs.d/emacs-rails" load-path)) (require 'rails)
Resourceful Links
Switching Up My IDE
That’s it, I can’t stand the bloat that comes from all things java anymore. I’ve been a pretty religious Radrails user almost since it’s inception. I haven’t been too frustrated with the recent lack of development because it’s done what I need it to do. About 4 months ago, I switched from using Radrails proper to loading it into an existing version of Eclipse as a plugin because I wanted to load some other types of plugins, like one for Erlang support. (Thanks pragprog!) This was serviceable, but since I’m running Ubuntu in a VMWare machine on my laptop I need to conserve all the RAM I can. The JVM for Eclipse currently runs at 86MB when sitting still. Totally unacceptable for my needs.
So, if I’m off the Radrails/Eclipse stack, what should I use? Another popular IDE is JEdit, but since the “J” stands for java, I’m skipping it. I’ve decided to take the time and learn how to use emacs. I love the emphasis on hotkeys and simplicity. Since emacs has been around in some form since 1974, it’s super stable too. It just seems that there is so much more I can do, and quicker too, if I’m just willing to take the time to learn. I am. Plus, there just seems to be some serious street-cred for telling people that you’re an emacs user.
Installation Instructions for Ubuntu Edgy
Since most of the development that I’ll be doing in emacs will be Ruby/Rails related, I’ll want to install Dima’s Rails Emacs minor mode. WARNING: This requires emacs 22, which you’ll either need to compile, or find a package for. There is an Ubuntu package of emacs 22 currently available in the repositories. It’s called emacs-snapshot and the package was built from CVS sources on 20060915, so it’s not the latest sources, but it’s pretty close. Feisty Fawn, which is supposed to release tomorrow (4/19) also has this package, but it’s actually built on 20070407, so very recently. I’ll be upgrading to Feisty soon. Just do the following to install:sudo apt-get install emacs-snapshotAs a final note, I like to keep all my programming utilities on the Gnome menu together, under the “Programming” heading. The emacs-snapshot package puts menu shortcut in Applications -> Accessories, so it required a little tweaking of the .desktop file. Fire up your favorite editor and edit /usr/share/applications/emacs-snapshot.desktop. Change line that begins with the word Categories to the following to move the shortcut to your Applications -> Programming section:
Categories=Application;Development;
I’ll take you through installing the Rails specific portions next time. Just to give a comparison, Eclipse uses 86MB of RAM just sitting there, while emacs uses only 11MB. I’m looking forward to getting my emacs pinky Why didn’t I switch sooner?
Fosterite: A Plugin for Some
I’d like to announce the release of my first contribution to the open source community, Fosterite. This plugin fills a need that I’ve had in my last 2 jobs. I’ve deployed Rails apps in 2 large companies where I’m not allowed to have direct access to the database or the a login to the production server. Frustration abounded since I was responsible for the stability of said application. I’m not going to go off on a Dennis Miller Rant here but let’s just say that sometimes large companies aren’t the smartest.
What it is
This plugin is a generator that will allow you to do some very “crude” administering of your application from a web interface. Install the plugin, generate a model and controller, and hook it up to your already rock solid authentication system and you’re ready to rock. See instructions below for the full install.
What you can use it for
You can execute queries directly against the database. (Be careful!) You can also run rake tasks. (YMMV) Finally, you can just get some information about the environment that your application lives in.
Where you can get it
For those of you who cannot be bothered with detailed instructions:ruby script/plugin install fosterite http://svn.devjavu.com/grokblok/rails/plugins/fosterite ruby script/generate fosterite MODELNAME [CONTROLLERNAME] rake db:migrateController name is not required, but I’d recommend it. Also, you’ll need to add a couple of snippets in your environment.rb file. Put this before the initializer call:
$APPLICATION_NAME = "[Insert your app's name]"and put this in the initializer call:
$LOG_PATH = config.log_path
For those that can be bothered, navigate on over to the Trac for more instructions and support.
Where I hope this is going
You can read about additional planned features on the wiki page. Something that I hinted at there, but haven’t put a lot of thought about is being able to restart your application from the web. Currently, if you had a rake task that would restart your mongrels or really any app server, I think it could be done, but you wouldn’t ever receive a response back. My line of reasoning is taking me down the path of perhaps using BackgrounDRB to pass the restart request to and then at least your could return a response before restarting.
Why would you want to do this? Well, say for instance you are at work and a rails security notice happens and you absolutely have to update to the latest tag. You’re somewhere that doesn’t allow SSH access, how would you currently do this? You couldn’t.
Useful Links
- Home http://www.grokblok.com/projects/fosterite
- SVN: http://svn.devjavu.com/grokblok/rails/plugins/fosterite
- Trac http://grokblok.devjavu.com/
Props to Dan for his Ruby-Fu
I just wanted to give a shoutout to Dan for his interview on Working with Rails. He finished 2nd in their Hackfest, and as a result, is going to RailsConf for free. Of course, my favorite part of the interview had to be the answer to the question about how Dan got involved with Rails:
When I started working for JPMorganChase I did web development in PHP. In the fall of 2005 Joshua Schairbaum, my colleague, started using Rails and really liked it. He encouraged me to check it out, and soon we were using Rails for all our small projects. After successful delivery of several small web apps, Josh was able to sell Rails to upper management, and we now use Rails for a very large access administration application.
The “sell” to upper management went pretty smoothly due to the fact that we were delivering, in no small part to Dan’s efforts. Neither he, nor I work at the monolithic bank anymore, but I think he’s going to be making some waves at Thoughtworks, just as I plan to do at my new employer.
I just want to say thanks, Dan! Also, in the interview, he mentions a plugin by our good friend, John X Andrews. I highly recommend that plugin for all your scoping needs.
Flash deprecation warning
DEPRECATION WARNING: @flash is deprecated!This was strange since the only usage that I had in either my controllers or views was like this:
flash[:success]
Well, the point of this little story is that Dan found a ticket describing this phenomena in detail. Here’s what happens, when you have a partial named _flash.rhtml that calls your flash object, an instance variable is created for the name of the partial, like normal. The problem was that the deprecation warning just looked for the creation of an instance variable named “flash”, not necessarily if it represented a flash object.
A patch was applied to edge 2 weeks ago that should fix this behavior. Thanks for the heads up, Dan! I’m not sure what the best practice around this should be. I’d imagine that the most common name for a partial that only contains your flash views would be _flash.rhtml, but perhaps there would be a more descriptive name for it, in order to get rid of some “coupling”. Perhaps something like _notifier.rhtml would be better.
Any thoughts?
Rails World Domination Tour '07
...it[Rails] can have a dramatic impact on the speed at which a Web development team is able to build and maintain enterprise Web sites and applications.
The emphasis in the quote is mine, and I think it’s very telling that Rails is being billed as an enterprise solution for companies because of it’s speed and maintainability. That pretty much sums up my experience with Rails thus far, and I think the first fruits of early adopters are starting to be harvested. Being a member of the second wave, I feel that I’m in a great position to be able to speak with authority on ways to ease Rails in the door at large corporations.
Equal parts design philosophy and development environment, Rails offers developers a few key code-level advantages when constructing database-backed Web applications.
If you are running or working in a large monolithic corporation and you’re not at least evaluating Rails’ position in your company, why not?
String Includes Enumerable
While working on a little side project, I’m using Rails app to do a lot of system calls and grabbing the response of STDOUT or STDERR. One of the things that has made this really easy is that in Ruby, String includes the Enumerable module, which treats the string as an array. This may not be a surprise, except that each item is separated out in the array by a new line character ”\n”. This allows the usage of the “each” method and all 28 other methods that come with Enumerable objects.
Controller:
def rake
@rake = `rake -T`
@tasks = []
@rake.sort.each { |line|
@tasks << line.gsub("rake", "")
}
end
If you want to iterate over the string character by character then you would have to iterate by byte and show the character value (the each_byte method returns the ASCII character number for the given character. You might do something like this to change all “a” characters to “e” characters:
@rake.each_byte do |b| b.chr.gsub(/a/,"e") end
In Rails, there’s a method called chars” which does some cool things by proxying your string to UTF-8-safe characters.
UPDATED: Dan Manges pointed out that I had a nonsensical example for each_byte.
On the Rails podcast
It’s really old news, but my coworker, Dan Manges and I were featured on the Official Ruby on Rails podcast. This was a great opportunity to showcase for the Rails community some of the cool things that we’re able to do inside the bank. You can download the interview directly from here.
