Search code examples
ruby-on-railsrubydesign-patternsrefactoringmodels

Logic of interaction among models in Ruby on Rails?


I'm studying Rails and am now trying to organize interaction among models. What I've written works, but I think that the code smells bad.

For example, I have two models with database tables Parcel and Warehouse. When I create a new Parcel, I want to increase the :current_weight of the Warehouse instance which is related to this new Parcel.

Again, everything works, but this type of code, interaction between two different objects, will be used frequently and something deep in my mind says: "Dude, this code sucks and will cause problems in the future!".

Maybe there are some good practices to organize or refactor it? Maybe it's better to create a universal module for such interactions, or even create method_missing logic to use methods with universal put_, remove_, check_, like warehouse.put_parcel and warehouse.remove_parcel.

In ruby console:

parcel = Parcel.new
parcel.weight = 10
parcel.warehouse_id = 1
parcel.save

# Create parcel and increase :current_weight of related warehouse by 10 after save

warehouse.rb:

class Warehouse < ActiveRecord::Base
    has_many :parcels
  attr_accessible :name, :current_weight
end

parcel.rb:

class Parcel < ActiveRecord::Base
    belongs_to :warehouse
    belongs_to :vehicle
  attr_accessible :name, :weight, :warehouse_id, :vehicle_id

  after_save :set_current_weight

  #Bad code:
  def set_current_weight
    @wh = self.warehouse
    @wh.current_weight = @wh.current_weight + self.weight
    @wh.save
  end
end

Solution

  • How about

    warehouse.parcels.sum(:weight)
    

    That way you are running a 'live' query based on the current data, rather the incrementing.

    Slightly more terse version of your current model too:

      def set_current_weight
        @wh = self.warehouse
        @wh.current_weight += self.weight
        @wh.save
      end