Search code examples
ruby-on-railsrubysingle-table-inheritanceform-forsti

Rails, STI and 'becomes' - f.object.errors not showing in view


My question is: why doesn't .becomes pass errors over to the new object? Isn't this the expected behaviour?


I have the following single table inheritance classes in a rails app:

class Document < ActiveRecord::Base
  validates :title, :presence => true
end

class LegalDocument < Document
end

class MarketingDocument < Document
end

I want to use the same controller and set of views to edit both LegalDocuments and MarketingDocuments, so I am using DocumentsController < ApplicationController with the following edit and update actions:

def edit
  @document = Document.find(params[:id])
end

def update
  @document = Document.find(params[:id])
  if @document.update_attributes(params[:document])
    redirect_to documents_path, :notice => "#{t(:Document)} was successfully updated."
  else
    render :action => "edit"
  end
end

and the following in my edit view:

<%= form_for @document.becomes(Document) do |f| %>
  <% if f.object.errors.present? %>
    <div class="error_message">
      <h4><%= pluralize(f.object.errors.count, 'error') %> occurred</h4>
    </div>
  <% end %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title, :class => "inputText" %>
  </div>
  <%= f.submit %>
<% end %>
  • If title is filled in, the documents update correctly.
  • If title is left blank, I am returned to the edit view BUT the error is not shown.

From debugging, I know it's not showing because f.object.errors is nil. However, from debugging, I also know @document.errors is NOT nil, as expected.


My question is: why doesn't .becomes pass errors over to the new object? Isn't this the expected behaviour?


Solution

  • Pretty much it is a bug and it should work as you initially expected. The following patch to address the issue looks like it was pulled back in October

    https://github.com/lazyatom/rails/commit/73cb0f98289923c8fa0287bf1cc8857664078d43