Search code examples
ruby-on-railscode-organizationview-helpers

Rails - finding the right place for common code


I have got myself quite befuddled. I have some code which takes some images, combines them and then spits out the combined image in .png format.

Originally this code was a method for a model - with the model's associations indicating which images to use. Thus:

class Component < Refinery::Core::BaseModel  
    drawing_accessor :drawing
  . . .
end

class Photo < Refinery::Core::BaseModel
  has_and_belongs_to_many :components
  has_many :drawings, :through=>:components

  def diagram
    . . . .
    Base64.encode64(png.to_blob)    #spit out the png as a base64 encoded string
  end
end

and in a view I could write

  <img src="data:image/png;base64,<%=@photo.diagram%>"

Now, I need to do the same combining of images, but directly from a list of component ids. As the component ids haven't been saved to a photo (and may not be) I need to move this code out of the photo model.

I want to able to call the same drawing code with a parameter that is a list (array or collection) of component ids, regardless of where they come from.

It seems that as the diagram comes from a set of components, it should belong with the components...somewhere.

In my various tries I end up with undefined method for an ActiveRecord::Relation, or for an Array.

Can you help clarify my thoughts about where this code belongs and how to call it?

thanks


Solution

  • Well, the Power of Posting has hit again.

    I put in a new route for the components collection:

      resources :components do
        collection do
          get :draw
        end
      end
    

    with a matching definition in the controller

    def draw                 
      send_data Component.construct(params[:list],params[:width], params[:height]), :type => 'image/png', :disposition => 'inline'
    end  
    

    and a method on the model to draw the components

      def self.construct(component_list, width, height)
      . . . 
        Base64.encode64(png.to_blob)    #spit out the png as a base64 encoded string
      end 
    

    The Photo model includes a method which pulls together the component list then call construct:

      def diagram
        component_list = []
        # construct the list of ids in the right order (bottom to top, or base to capital)
        ....
        Component.construct(component_list, self.image.width, self.image.height)
      end
    

    And from javascript I can call

    var component_list = $("input:checked").map(function(){return this.value}).get();
    . . . 
    $.get(url,{list:component_list, width:width, height:height}, function(data) {
      $('img.drawing').attr("src","data:image/png;base64," + data);
    })
    

    I still have doubts about including the methods in the models and not somewhere in a view or view helper, but this does seem to work!