In my application, these "planners" (essentially, article ideas) follow predetermined templates, written in Markdown, with some specific syntax here:
Please write your answer in the following textbox: [...]
Please write your answer in the following textarea:
...So here, on line, you should write one thing.
...Here, on line 2, you should write another.
...
...
...
Essentially, [...] is a text input, and a group of lines starting with ... are a textarea. That's not really the issue - it's just to explain what part of this code is doing.
On actions new and edit, the standard planner form is displayed, with the correct fields based on the template (for new) or current planner body (for edit). On save, the template's fields are filled in with params[:fields], and the resulting Markdown is saved as the planner's body. The code, I'd hope, is now possible to follow, knowing this context. Only relevant controller code is provided, and it uses make_resourceful.
class Staff::PlannersController < StaffController
  make_resourceful do
    actions :all
    before :create do
      find_planner_format
      if @planner_format
        current_object.body = fields_in_template @planner_format.body
      else
        flash[:error] = 'Planner format not found!'
        redirect_to staff_planners_path
      end
      current_object.user = @current_user
    end
    before :update do
      current_object.body = fields_in_template(current_object.body)
    end
  end
private
  def fields_in_template(template)
    fields = params[:fields] || {}
    if fields[:inline]
      template.gsub! /\[\.\.\..*\]/ do
        "[...#{fields[:inline].shift}]"
      end
    end
    if fields[:block]
      template.gsub! /^\.{3}.*(\n\.{3}.*)*$/ do
        fields[:block].shift.split("\n").collect { |line|
          "...#{line}"
        }.join("\n")
      end
    end
    current_object.body = template
  end
end
And now, the mystery: in the update action, changes to the body are not saved. After debugging, I've determined that the issue does not lie only in current_object.save, since the following before :update code does what you would expect:
before :update do
  current_object.body = 'test string'
end
In fact, even this gets the expected result:
before :update do
  current_object.body = fields_in_template(current_object.body) + 'a'
end
So now, the question: why is Rails so insistent that it not save the result of the function - and even then, only when it comes from update? More debugging showed that the object attribute is set, and even claims to save successfully, but reloading the object after save reverts the changes.
At first it looked like the resulting string was just a "poisoned" variable of sorts, and that rebuilding the string by appending "a" removed that strange state. However, the following code, which ought to add an "a" and remove it again, also failed to save.
before :update do
  new_body = fields_in_template(current_object.body) + 'a'
  new_body.slice! -1
  current_object.body = new_body
end
This is just bizarre to me. What am I doing wrong here, and what can I possibly do to debug further? (Or if you happen to instantly see my mistake, that'd be nice, too...)
EDIT: After checking SQL logs (not sure why I didn't think to do this earlier), it would seem that Rails doesn't seem to acknowledge the new body attribute as actually being different, even though checking the string in the debugger confirms that it is. As such, Rails doesn't even run an UPDATE query unless something else is modified, in which case body is not included.