UniThrive.org is a fantastic new non-profit startup that seeks to help reduce the cost of higher education by networking college students with alumni, and facilitating direct, zero-interest loans between alumni and students to defray tuition costs.
Technologically, UniThrive is a Rails application that began as a fork of the open-source social networking application Insoshi. Since forking Insoshi, we've nearly doubled the size of the code.
Today, UniThrive is in a live beta test available to students and alumni of Harvard University. Take a look, and check out the UniThrive Blog!
I'm converting an old, controller/action/id style Rails application to a more RESTful way of doing things, and ran into a brief roadblock: one of my main tables uses single table inheritance to generate three subclasses of items. I never actually use the superclass "task", I only use the three subclasses "action item", "work order", and "problem report".
So, I ran into this little challenge: all three STI subclasses use the same controller, "tasks", because they all have essentially the same behavior and differ only in minor details. But, when I do a resources map:
map.resources :tasks
Then I get errors in much of my code when I say things like redirect_to @task, because if that task happens to be an ActionItem, it's trying to call action_item_path(@task), which doesn't exist.
I googled around a bit to no result. Striking out on my own, it turns out the answer is as simple as mapping each resource independently, and just overriding the controller in map.resources:
I'm following Chapweske's approach of blocking mass assignment by default in all models, by putting this line in an initializer:
ActiveRecord::Base.send(:attr_accessible, nil)
This had the expected side effect of breaking several zillion tests, because tests frequently use things like Model.build() and Model.create!() to generate on-demand fixtures during testing. Hartl has a great bit of code that creates unsafe_build() and unsafe_create() methods in ActiveRecord. You can use these methods instead of build() and create() to function as expected in your tests.
This works great, except that I also use the mass-assignment method update_attributes! in my tests and specs frequently, particularly when I want to spec the effect a change on one model has on an associated models' methods. So, I expanded on Hartl's helper code a bit, to give myself the necessary methods. In case it helps anyone else:
/lib/initializers/unsafe_build_and_create.rb
class ActiveRecord::Base
# Build and create records unsafely, bypassing attr_accessible.
# These methods are especially useful in tests and in the console.
def self.unsafe_build(attrs)
record = new
record.unsafe_attributes = attrs
record
end
def self.unsafe_create(attrs)
record = unsafe_build(attrs)
record.save
record
end
def self.unsafe_create!(attrs)
unsafe_build(attrs).save!
end
def unsafe_update_attributes!(attrs)
self.unsafe_attributes = attrs
self.save!
end
def unsafe_update_attributes(attrs)
self.unsafe_attributes = attrs
self.save
end
def unsafe_attributes=(attrs)
attrs.each do |k, v|
send("#{k}=", v)
end
end
end
So I'm hammering away at a project tonight, writing a few specifications for a module. I've changed very little - or so I think - when five of my specifications start reporting this error:
NoMethodError in 'LoansController POST 'create' with valid parameters should succeed'
undefined method `env' for
This happens on the line where I call post :create in a controller spec. Undefined method 'env'? What's that about? I'm certainly not trying to call a method named "env".
It took me a little bit to figure out what was going on. See, this series of tests needed access to a particular LoanRequest object I was pulling out of fixtures. So I'd put above the tests:
before(:each) do
... some other stuff ...
@request = loan_requests(:johns_loan_request) # fetch fixture
end
Well, kids, it just so turns out that it's a bad idea to overwrite the @request instance variable in any rails context. Who knew?
Come to think of it, it would be nice to change the accessibility and/or mutability of Rails' basic instance variables and classes to prevent this kind of accidental overwrite by the programmer. Because when you make that mistake, it's invariably a bit of a pain to figure out because the error it causes is obscure.
Maybe I'll have to dig into the code one of these days to see if anything can be done about it.
I've been playing with Sass and Haml in my rails projects the last few months. While I'm a bit ambivalent about Haml, I've wholeheartedly adopted Sass. A friend just forwarded me this post at fecklessmind, which excoriates Sass as a maintainability nightmare.
While I understand the guy's complaints, I have to say I disagree. I think he's complaining about a code convention that he shouldn't be following in the first place, rather than the underlying language, and he's ignoring some of the other most useful things Sass brings to the table.
Nesting in Sass
One of the most common problems I've faced over the last eight years of writing stylesheets is interfering selectors. When you have a complex cascading selector, it's often not obvious exactly where it will apply, because of the way priorities work. So a hundred times I've set some styling on UL's and LI's (thinking of ones in my #content block), only to have them accidentally interfere with the layout of my suckerfish dropdowns back in #nav.
That's an easy case, but sometimes with complex selectors it can be hard to figure out who's interfering with whom. However, once you've found the culprit, the solution is generally to go back and wrap all of the rules in an outer selector, changing all of my li {rule} selectors to #nav li selectors, or whatever. When you have twenty different rules in that section, doing this is a royal pain in the butt. Especially when you have multiple tag selectors on one line: it's seriously annoying to change the nice clean h1, h2, h3 to #content h1, #content h2, #content h3!
When you do need these wraps, Sass makes it super easy via auto-nesting:
#nav
li
:color #whatever
:float left
a
:whatever etc
will compile to: #nav li {
color: #whatever
float: left
}
#nav a {
whatever: etc
}
Now, the author of fecklessmind is complaining about how this makes rules harder to find, and how it slows down parsing. Both of these can be true, if you overdo it. But I don't - Sass doesn't force you to wrap your rules this way, and I frequently don't when it doesn't provide any benefit or when it would cause me to write redundant rules. I can and frequently do write single-line cascading selectors, and rules without wraps at all - the very things fecklessmind is complaining that Sass takes away from him.
Nothing about Sass prevents me from writing things like this: body #nav ul li a
:float left
or even #content h1, #nav h2, .article h3, p h4
:font-weight bold
If that's really what I want to do. I learned how and when to wrap selectors with a near-decade of writing CSS, and I apply those same guidelines when I write Sass - Sass just makes it easier when I do want to do it.
The benefits of nesting early
While I don't use Sass nesting everywhere I possibly could, I do often use it slightly more than would be absolutely required.
The reason is that it heads off a lot of annoying bugs with interfering selectors. For example, say a rule I wrote for .article .body p, and it's not getting applied. After some sleuthwork (long, painful, frustrating sleuthwork if I'm on a platform without firebug, like IE), it turns out this is because there's a #content p rule 2000 lines earlier in the CSS file that's obscuring it. When I nest things in Sass to create a clean cascade hierarchy, this kind of interference is far less likely to occur in the first place.
Meanwhile, the other benefits of Sass
CSS is riddled with problems, and Sass solves two of the most egregious: magic numbers/constants, and compiled server-side imports.
Eliminating magic numbers in CSS
For constants, Sass lets me define commonly used tokens (like colors, for example), and reuse them throughout my stylesheets. This means if I want to adjust a color, I can change it in only one place and the result is reflected throughout my code. Very handy:
!main_link_color = #48950a
Now, if the client says "make the links blue, not green", I can change that constant and it gets automatically reflected everywhere else. Brilliant.
Organizing my code
fecklessmind says this:
... imagine that the stylesheet is 5000-lines long and you’re looking for p selector, rather than #article. In classic CSS you could just search for #main p, but in Sass they are miles apart. Swell, isn’t it?
A five-thousand-line line file?You're doing it wrong. No code should ever look like that. CSS is the only major language that compels you to work that way and Sass fixes it.
Every good programming language lets me put my code across multiple files, in a nice, organized heirarchy. One class per file and all that: essential for readability and maintainability. But if I use CSS, I can't very well organize my stylesheets into multiple files. If I do, I have to import them client-side, which generates extra hits for the user's browser and extra load for my server. As a result, CSS files tend to be monolithic multiple-kiloline monstrosities.
Sass fixes this. If I use @import to import a Sass file into another Sass file, Sass automatically and transparently compiles that server-side and ships out a single file to the user.
The result is that, writing Sass, I often have 20-30 files containing only a page or so of code, each for a specific feature or layout section. The client still only sees screen.css (and maybe print.css, mobile.css, and ie6.css), but screen.css contains the compiled contents of layout.sass, nav.sass, links.sass, content.sass, footer.sass, etc. In case I need to scan through the compiled screen.css and figure out where a rule came from, I start each file with a single comment containing the name of the file; /*------ nav.sass and such.
If the rule is for paragraphs that could appear anywhere in #main, in my Sass code it would be a file called main.sass, which is usually a relatively short file; 50-60 lines. (All the things destined for other elements would appear in articles.sass, or calendar.sass, or data_tables.sass, keeping main.sass short for only the universal elements).
That logical grouping — the way every other programming language does it — helps me find my CSS rules much more quickly, I think, than fecklessmind's "search for one-line selectors" would. Because with his approach, I might think I'm searching for #main p, when in fact what I really want is #main .section p, and thus my search won't find it.
In reality, there's no way to make a single 5000-line file easily maintainable, period. fecklessmind's little tricks are just that: tricks built from years of experience working in a broken system. Better to use logical organization to solve the problem, and Sass lets me do this.
The bottom line is, badly-written Sass could be horrible to maintain, and maybe worse in some ways than badly-written CSS (but better in others, particularly in weird cross-reactions between unwrapped css selectors). But the same is true of badly-written code of any type. And in my experience Sass gives me much better tools to write maintainable stylesheets than CSS alone does.
I've been working a lot this week with sphinx and ultrasphinx on a project that's a fork of Insoshi. Insoshi is in the process of switching search from ferret to sphinx, and sphinx has been integrated into the Insoshi edge branch.
I've had dozens of problems, in fact it's fair to say I've spent upwards of 15 hours just debugging ultrasphinx and getting my tests to pass. There were several problems; here are the main three and how I fixed each one.
This should be useful to anyone upgrading Insoshi to the sphinx version, or to anyone else trying to get ultrasphinx working in their Rails project. I definitely don't recommend starting with this post if you're just starting out with sphinx. Instead, go read this much better introductory tutorial from the guys over at Insoshi. Then if you have problems, come back here and you may find solutions.
Getting search tests (or specs) to pass with sphinx
This one is pretty simple, in retrospect, but it can be frustrating and opaque if you are used to ferret. Unlike ferret, sphinx (at least via ultrasphinx) runs only via a daemon. Where acts_as_ferret uses a daemon only for the production environment and just accesses the index files directly in test or development, ultrasphinx can only get to the indexes through the daemon.
So, to run your tests, you just build up the indexes for test and run them. In this case, I'm running the specs for Insoshi's searches controller:
The problem, of course, is that it doesn't work! The reason is that db:test:prepare creates the structure of your database, but doesn't load any of your fixtures as data: the test db is empty.. So when you run the index command, an empty index is built. You can see this from the output of that first index command, which will look something like this:
collected 0 docs, 0.0 MB
total 0 docs, 0 bytes
total 0.078 sec, 0.00 bytes/sec, 0.00 docs/sec
Ultrasphinx has built an empty index.
The solution
The solution, believe it or not, is to run the tests, let them fail, re-index, and run the tests again (Many thanks to Long Nguyen at Insoshi for helping me figure this one out):
The first attempt to run the specs loads the fixtures, and leaves them in the database, thus letting the subsequent index command build an actual index.
Running sphinx for both test and development environments at the same time
The next big challenge was enabling behavior-driven development. I like to work with autotest and growl running constantly in the background. But this was tough to do with sphinx, because the daemon needed to be stopped and re-started, and the index re-created for each environment, alternately running all of the above commands either with or without RAILS_ENV=test.
The solution is to set up your ultrasphinx base configuration to completely separate both the test and development indexes and to let the daemons for the two environments listen on different ports. I had tried something like this and come close, but not quite, when Long at Insoshi again bailed me out. You need to change the port (in two places), and the paths of the logs, pidfile, and index directories so that test and development daemons are using entirely separate resources. Here's a diff of my test.conf and default.conf:
The sql_range_step is related to the next issue, which is that sphinx does not play well with foxy fixtures. Anyway, make the above changes and you should be able to run test and development sphinx daemons at the same time:
If it worked, you should see separate indexes in $RAILS_ROOT/sphinx and $RAILS_ROOT/sphinx_test, and two daemons running, which you can confirm with ps waux | grep searchd: evan 1339 0.0 0.0 78100 292 s000 S 5:37PM 0:00.52 searchd --config /config/ultrasphinx/test.conf
evan 1326 0.0 0.0 78100 292 s000 S 5:36PM 0:00.68 searchd --config /config/ultrasphinx/development.conf
Getting sphinx to play well with foxy fixtures
The next problem I discovered was that on some machines, but not others, running my search specs would result in these weird errors: 1)
ActiveRecord::RecordNotFound in 'SearchesController Person searches should search by name'
Couldn't find Person with ID=328556765
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:308:in `reify_results'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:286:in `each'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:286:in `reify_results'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search.rb:362:in `run'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:352:in `perform_action_with_retries'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search.rb:342:in `run'
/var/www/domains/unithrive/app/controllers/searches_controller.rb:38:in `index'
./spec/controllers/searches_controller_spec.rb:51:
script/spec:4:
When I poked into this "Couldn't find Person with ID=328556765" error, it seemed like sphinx was almost working. The index was set up, and the search was finding someone in the index during the test. Ultrasphinx was passing back the id 328556765, which didn't exist in the database. So why would Sphinx "find" a record in its index but then pass back an ID for a database record that didn't exist?
And furthermore, why would it work on one machine, but not on another?
The brainstorm came when I checked what the actual database IDs were for this particular record, with Person.find_by_name("fixtures' name").id. On machines where it worked, the id was a huge number (is it generally is with foxy fixtures), but on machines where it didn't work, the id was an even huger number.
Sphinx tries to make sure that all items that get indexed have a different index in sphinx, and it does this by multiplying all of your id's by N, where N is the number of models getting indexed, and adding an offset of 0 for the first model, 1 for the second, etc. This guarantees that every record from every table will have a unique id. In the case of this application, all of my Person records were getting indexed by sphinx as (Person#id * 4 + 2).
Danger, Will Robinson: 32-bit int rollover!
The problem is that foxy fixtures generate their own ids from a hash of the fixture label, and those ids can be anywhere in the 32-bit unsigned integer space. But Sphinx also stores ids as 32-bit unsigned integers. This means if you happen to get a large fixture id, and then sphinx multiplies it by 4 (or whatever; it could be higher if you have more indexed models), your id will rollover and come out as (id * N + n) % (2^32). Sphinx will store that result, and then when it finds the record in a search, it will try to recreate the original id by subtracting n and dividing by N ... giving you the wrong id. Your test will fail to find the record.
Incidentally, this problem with foxy fixtures is why your test.base file needs the line sql_range_step = 999999999. Sphinx builds indexes by searching a few ids at a time. But the ids generated by foxy fixtures are so big that if sphinx only collects them in ranges of 5000 at a time, it will take forever to find them all.
I'm working on a plugin that monkeypatches foxy fixtures to create sequential, low-numbered IDs. In the meantime, you can just compile sphinx to support 64-bit ids, which should give you plenty of headroom to handle foxy fixture ids multiplied by N in sphinx*:
In your sphinx source directory:
configure --enable-id64
make
sudo make install
That should do it. Let me know in comments if any of this information helped you.
*At least until you start approaching 2^32 models in your application, that is.
This is pretty basic and there's plenty of documentation on the web, but this morning I found it difficult to locate with a google search. Maybe I just didn't know the right terms. (searching "git repository change origin" seems obvious to me, but the results were useless.) Hopefully this post will help people find the documentation they are looking for if they are searching the same way I was.
Anyway, suppose you have a local git repository that you cloned from some remote repository at, say git://user@dev.foo.com/git/repos/path, and you've been happily pulling, pushing and rebaseing to and from that remote repository. But now you or your team leader have moved that remote repository to a new location, and you'd like to point your repository to the new URL without having to do a full checkout.
What you need to do is change your 'origin' setting. Unfortunately, there's no trivially easy way to do this from the command line in current versions of git. Instead, you edit .git/config in your project root, which may look something like this:
All you need to do is edit that file with your favorite editor and change the url = setting to your new location. Assuming the new repository is correctly set up and you have your URL right, you'll be happily pushing and pulling to and from your new remote location.
In one of my Rails projects, I maintain a user-visible log of updates to the database by recording entries into a table that looks like this (from schema.rb):
Whenever a record is created, updated, or deleted, I create and save an instance of LogEntry, containing for example {:table => 'task', :action => 'update'} and in the 'changes' column I save a serialized hash showing which attributes of the task object changed before and after save. In addition, I save which logged-in user made these changes, and when.
This is convenient, it gives my client a log that's much more user-accessible and allows them to easily back-trace who did what to the database and when, which is important for their process and certain certifications.
When I upgraded the project to Rails 2.1 a couple of weeks ago, most of the code still worked fine, but the hashes showing the object changes were no longer showing up in views of the log. The culprit turned out to be Rails 2.1's new dirty feature. Why? Because it adds the method 'changes' to ActiveRecord::Base. This is a great new feature that lets you know what has changed to an ActiveRecord object since you loaded it from the database, with all kinds of benefits like doing more selective updates, or not writing to the database at all if no changes have occurred, thus reducing system load if you call save! a lot.
Unfortunately, the new method 'changes' was obscuring my attribute 'changes' in some circumstances, and at the very least confusing the heck out of me, the programmer.
The solution, of course, is not to name your fields anything that corresponds to any Ruby core method or any method of ActiveRecord::Base. I fixed my problem with a migration to rename the column 'details':
def self.up
rename_column :log_entries, :changes, :details
end
def self.down
rename_column :log_entries, :details, :changes
end
This morning we launched a refreshed site and an all-new online store for one of my clients, CordobaSzekely Productions.
Robert Cordoba and Deborah Székely are dance instructions and multiple-time national champions at the U.S. Open West Coast Swing Championships. They teach West Coast Swing and other dances all around the US and the world, and market a line of dance instructional DVDs.
Their former site had gotten a bit long in the tooth, so this was a just a quick refresher, keeping the former graphics design but bringing the HTML and CSS up to contemporary standards. Their online store was completely reimplemented using the open-source Zen Cart, where formerly they'd used the proprietary (and often difficult to use) Miva Merchant.
Sometimes you may want to generate a selector with a fixed set of options. In one recent task of mine, we needed a selector for an integer 1 through 10, but the client wanted them labeled also with text to identify how the numbers mapped to the words "High" "Medium" and "Low". (We were selecting the priority level of a task in a project management application). Essentially, I want to generate this HTML output:
These are fixed name/value pairs, so it made sense to me to store them as a constant hash in my Task model:
However, I was rather dismayed to discover that this didn't produce the results I wanted, because Ruby hashes (in Ruby 1.8.6) do not preserve order. This is what came out:
That's not what I wanted! I knew that select will also take arrays, but of course I needed separate name/value pairs, which I can't get with just straight arrays. I spent a while playing around with OrderedHash, which exists in Rails but is essentially undocumented and, as it turns out, does not support any useful functions of Hash like merge! and insert! that might make it easy to construct my list of options.
The Fix: Array of Arrays, or Array of Hashes
The documentation is not entirely clear on this, but if you send an array of 2-element arrays to select, rails will use the two elements of each inner array as if they were key and value pairs, and because the entire structure is an array it will preserve order. So, to get the results I wanted, I just need to change my constant to this:
As it turns out, the way ActionView processes the options is fairly general: if you pass it any enumerable object, it will iterate that object, and for each element will check to see if that element supports the methods :first and :last (and isn't a string). If so, it will generate an option with the text set to element.first and the value set to element.last. If it was a string, or didn't support first and last, both the text and value of the option are set to the element itself.
Testing it
Here's a handy function I use for testing it the presence of a selector. You pass it the name of your selector, the name of hash or array of options (in the any format supported by select), and optionally the value of an item that should be pre-selected, and it will assert the existence of each of those things. If you need to handle selectors with multiple selections, you can just wrap the last assertion in a loop.
Drop this in test/test_helper.rb
# Assert existence of form select input
# the
#
# or as an array like this:
# [ 'foo', 'bar' ] will be asserted to match
#
#
def assert_select_input(name, option_values, options={})
attributes = { :name => name }
# first assert that the select tag exists
selector = { :tag => "select", :attributes => attributes }
assert_tag selector
option_values.each do | opt |
if !opt.is_a?(String) and opt.respond_to?(:first) and opt.respond_to?(:last)
assert_tag({:tag => "option", :attributes => { :value => opt.last },
:parent => selector, :content => opt.first })
else
assert_tag({:tag => "option", :attributes => { :value => opt },
:parent => selector, :content => opt })
end
end
# check for the pre-selected option, if any
if options[:selected]
assert_tag :tag => "option", :attributes => {:selected => 'selected',
:value => options[:selected] }
end
end
As an example of how to use it, here's my method for testing the task priority selector pictured above:
# asserts a
Where the array specified in the Task model looks like this: