Topic: Bizarre methods breaking in production:

Several methods that work fine on my machine break spectacularly in production. Anyone's help would be appreciated enormously--I was hoping to be on time with this project....

Here's an example:
I have a method called extended_create in my Piece class that takes the contents of [:content_assignments] in the params hash, builds a PieceAssignment object, and associates it with a given Piece. Here's what the method looks like:

  def extended_update(params)
    piece_assignment = ContentAssignment.find_or_create_by_piece_id(:piece_id => self.id)
    piece_assignment.piece_type_id = params[:content_assignments][:piece_type_id]
    piece_assignment.page_id = params[:content_assignments][:page_id]
    self.content_assignment = piece_assignment
    save!
  end

It works perfectly on my local machine. When we push to production though, things get weird. From the production.log:
Processing AdminController#create (for 67.166.121.58 at 2007-06-01 00:40:51) [POST]
  Session ID: d9e02a1420f35727a114758ecb12ab73
  Parameters: {"commit"=>"Create", "content_assignments"=>{"piece_type_id"=>"5", "page_id"=>"3"}, "action"=>"create", "controller"=>"admin", "piece"=>{"header"=>"Search All Listings", "content"=>"", "partial_name"=>"rmls", "is_dynamic"=>"true"}}


ActiveRecord::StatementInvalid (Mysql::Error: Column 'page_id' cannot be null: INSERT INTO content_assignments (`page_id`, `piece_type_id`, `piece_id`) VALUES(NULL, NULL, 1)):


As you can see, the parameters are being passed just dandily. Between the passing and the insert statement, things get lost. Why does this happen on the production system after a cap deploy and not locally? Baffling.

Another class is having little fits as well. The extended_create method on the PieceType class refuses to be acknowledged:

NoMethodError (undefined method `extended_create' for #<PieceType:0x2b6ce97248a0>):

But here is the contents of piece_type.rb, inside my current directory!:
class PieceType < ActiveRecord::Base
  has_many :content_assignments
  has_many :pages, :through => :content_assignments
  has_many :pieces, :through => :content_assignments

  def extended_update(params)
  end
 
  alias extended_create extended_update
 
end


Moreover, it shouldn't even be calling that method in the first place! An attribute called extended_form contains either "true" or nothing. Whether the extended_create method is called depends on whether or not extended_form is true for a given class, and it's not for PieceType. (This value is pulled from the database.) Once again, works like a charm on my machine, ushers the apocalypse in production.

Guys, I am really perplexed.
I have been finagling with this site and my production environment for months now, and I'd really like to get some Rails sites up and running best-practices style.
This stuff is a little discouraging. I know it all comes together eventually, but is there a reason it all seems this tricky?

Thanks in advance for any help!

Last edited by terov (2007-06-01 01:48:35)

Re: Bizarre methods breaking in production:

Fixed the second of the two errors by switching over to ActiveRecordStore for my session handling.

The first is still a bugaboo. Thoughts?

Re: Bizarre methods breaking in production:

Can you post the controller action which calls the extended_update method?

Railscasts - Free Ruby on Rails Screencasts

Re: Bizarre methods breaking in production:

Sure. I realize this isn't the most RESTful way of going about things, but it's a little late in the game to change it now. Will have to be a major 2.0 refactoring.

(I've also attached another method that might be relevant.)
admin_controller.rb:

  def create
    get_names_and_model(session[:selection])
   
    @item = @selected_class.new(params[@admin_selection])
   
    @selected_class.transaction do
      if @item.save
        unless @extended_form.nil?
          @item.extended_create(params)
        end   
        flash[:notice] = @class_name + ' was successfully created.'
        redirect_to :action => 'list'
      else
        render :action => 'new'
      end
    end
  end

  def get_names_and_model(selection)
    is_present = AdminSection.find(:first, :conditions => "model_name = '" + selection + "'")
    if not is_present.nil?
      @admin_selection = selection
      @class_name = selection.camelize
      @selected_class = Kernel.const_get(@class_name)
      if (not is_present.extended_form.nil?) and (is_present.extended_form == 'true')
        @extended_form = @admin_selection
      end
    else
      admin_menu
      render :action => 'admin_menu'
    end
  end


Thanks a million ryanb!

Re: Bizarre methods breaking in production:

I don't see a call to extended_update there. Perhaps it's in your "update" action?

Railscasts - Free Ruby on Rails Screencasts

Re: Bizarre methods breaking in production:

Oops! Sorry about that. Here's the update method, as well as the edit and new methods, just in case:

  def update
    get_names_and_model(session[:selection])
    @item = @selected_class.find(params[:id])   
    @selected_class.transaction do
      if @item.update_attributes(params[@admin_selection.to_sym])
        unless @extended_form.nil?
          @item.extended_update(params)
        end     
        flash[:notice] = "#@class_name was successfully updated."       
        redirect_to :action => 'show', :id => @item
      else
        render :action => 'edit'
      end
    end # transaction end
  end

  def edit
    get_names_and_model(session[:selection])
    @item = @selected_class.find(params[:id])
  end

  def new
    get_names_and_model(session[:selection])
    @item = @selected_class.new
  end

Re: Bizarre methods breaking in production:

Oh, I just noticed the log calls the "create" action so it is calling extended_create. But in your original post you have the extended_update method. Can you post extended_create?

Railscasts - Free Ruby on Rails Screencasts

Re: Bizarre methods breaking in production:

It's just an alias for extended_update:

alias extended_create extended_update

Re: Bizarre methods breaking in production:

The "find_or_create_by_piece_id" method will try to save the model at that point if it doesn't find a record with that piece_id. Perhaps you want "find_or_build_by_piece_id"?

Railscasts - Free Ruby on Rails Screencasts

Re: Bizarre methods breaking in production:

find_or_initialize_by did the trick!

You are the man smile

Also, your screencasts rock. Thought you should know.