Epoch's Blog

A wolf doing tricks. A very procrastinatory wolf.

Singleforest and Litsocial Down

| irl

I had to disable singleforest.com and staging.litsocial.com. There’s a extremely bad security bug in rails I haven’t had time to patch. The bug is already in metasploit which means an automated attack could compromise my servers.

I’ll be working over the weekend to patch my applications. I have several applications at my current job that are going to need emergency patches.

Update 2013-01-19: Both sites are back online.

Why Autosave Doesn’t Work on Belongs_to Associations

| programming

This post relates to Rails 3.2. It probably applies all the way back to Rails 2 but I make no guarantees of past or future applicability.

The rails docs on association autosave for belongs_to currently reads

If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. If false, never save or destroy the associated object. By default, only save the associated object if it’s a new record.

ActiveRecord::Associations::ClassMethods Rails Docs

Clear enough. So you would expect this code to work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Story < ActiveRecord::Base
  belongs_to :user
  belongs_to :series

  # nested_attributes_for doesn't work on belongs_to association
  # so we duplicate a subset of that behavior for new records
  attr_accessor :series_title

  before_save :save_series_title, if: ->(o){ o.series_id.nil? && o.series_title }

  def save_series_title
    self.series = user.series.find_or_initialize_by_title(series_title)
  end
end

What the documentation doesn’t tell you is that this autosave for a belongs_to association is implemented as a before_save callback. This is obviously going to throw a wrench in things. Other associations like has_may and has_one are implemented in a after_create/after_update callback.

The solution for the example is rather simple.

1
2
3
4
5
def save_series_title
  self.series = user.series.find_or_initialize_by_title(series_title)
  # Need to manually save since the autosave callbacks have already been called.
  self.series.save
end

Calling save at the last line of the function will maintain the same functionality of the autosave callbacks. If the association fails to save, the callback returns false, the save is aborted and the transaction is rolled back.

Why this behavior exists

The save order for belongs_to callbacks is different for a very simple and logical reason. The foreign key for a belongs_to association is on the record that is being saved. So the association needs to to be saved before the record it’s on so it can set the field before the query is executed. For the same reasons has_many and has_one associations save after the query executes since those associations need to wait for the record to have an id before they can be saved.

New Blog.

| irl

Working on moving my blog from posterous to my own hosting.

Net::HTTPBadResponse: Wrong Status Line: ””

| programming

If you ever see: Net::HTTPBadResponse: wrong status line "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"

Then you probably forgot to use ssl with your request to port 443. Apache coughed up a 400 error page over ssl in a way that caused the ruby standard library Net::HTTP to vomit exceptions all over your application.

This behavior was discovered on with Ruby 1.8.7 patch level 352. Judging by how it affected all the development system at my work, it affects all Ruby 1.8.7 patch levels equally. I have no ideal what happens with Ruby 1.9.

Singleforest Beta Soon (for Real)

| singleforest

So close, I can taste it. Singleforest is nearly ready for beta. I’ve hammered the most the major bugs I’m aware of.

What’s left before launch?

  • Some of the custom logging code is storing passwords. That needs to get fixed before the site can go live.
  • Moving the server from Rackspace to WebbyNode. Waiting on WebbyNode to get debian 6 out. Will go with Ubuntu in a pinch.
  • Need to write up Terms of Service and Rules documents.

Some of the issues getting the site ready:

  • Getting SSL/nonSSL redirection working properly was not happening.
    • Moved the entire site to ssl instead. Easier and more secure anyway.
  • Getting tests written for some of the code. RSpec fought me every step of the install process.
    • Releasing the beta with only minimal test coverage, will add tests as bugs pop up.
  • Writing my own css was taking way too much time.
    • Purchased a theme for $20
    • Will fix some of the icky coloration later. (background too bright, link color too light)
  • Event system was pretty complicated and was breaking a lot of code
    • Stripped events and notifications to the minimum that was required and stopped trying to ensure they get saved.
  • Spending too much time making the ajax stuff nicer
    • Stopped working on writing my own widget library and settled on a just works solution for now.

I can’t wait to for this thing to be live. It’s been way too long.