如何设计你的宝石,以便它们与Rails模型很好地连接?

时间:2011-11-07 16:06:34

标签: ruby-on-rails ruby ruby-on-rails-3 rubygems

假设我编写了一个gem,它会对Google Distance API进行惰性调用并使结果可用。像这样:

module GoogleDirections
  class Journey
    attr_reader :directions, :origin, :destination

    # Origin and destination can either be string addresses or
    # pairs of lat,long co-ordinates
    def initialize(origin, destination)
      @origin = origin.is_a?(Array) ? origin.join(',') : origin
      @destination = destination.is_a?(Array) ? destination.join(',') : destination
    end

    # calculate the trip distance
    def trip_distance
      @trip_distance ||= directions.inject(0){|sum,leg| sum += leg["distance"]["value"] }
    end

    # This method requests directions from Google when we need to
    def directions
      @directions ||= JSON.parse(# get the directions from )
    end
  end
end

所以,现在我在我的Rails项目中添加这个gem。 Tis rails项目有总线和目的地的公共汽车。所以我想要做的是在保存到数据库的路线之前向谷歌查询路线。

class Bus < ActiveRecord::Base
  before_save :set_trip_distance

  def set_trip_distance
    self.trip_distance = GoogleDirections::Journey.new(self.origin, self.destination).trip_distance
  end
end

但是如果我在我的宝石中添加一个行程持续时间方法,我可能最终也会在我的总线模型上设置它。显然,如果我这样做,我应该提取一个Journey实例的创建。

class Bus < ActiveRecord::Base
  before_save :set_trip_distance, :set_trip_duration

  def journey
    GoogleDirections::Journey.new(self.origin, self.destination)
  end

  def set_trip_distance
    self.trip_distance = journey.trip_distance
  end

  def set_trip_duration
    self.trip_duration = journey.trip_duration
  end
end

set_trip_distanceset_trip_duration方法似乎彼此非常相似。我可以想象一下我可能在公交车上设置6种不同的路线属性。这让我觉得我必须有一个更好的设计模式。

我想我可以设计Gem,我可以include它,但这样做会增加Gem和我的公共汽车上的列名之间的耦合,这看起来很糟糕?

什么是最佳选择?

1 个答案:

答案 0 :(得分:0)

如果您想让用户有机会为Journey数据命名自己的列,那就是他们必须做的事情。

但是,如果已经有了一段旅程,为什么不把它作为一个关联,或者在一些元编程下进行包装呢?

class Bus < ActiveRecord::Base
  has_journey :journey
  # Could define journey origin/dest in terms of Bus fields:
  has_journey :journey, :origin => :starting_loc, :destination => :ending_loc
end

那就是说,取决于你实际实施的是什么,看起来更像是一辆公共汽车将有多次旅行,除非它是一次性公共汽车。这将允许一些有趣的东西,如预定的日记,旅程历史等。

class Bus < ActiveRecord::Base
  has_journeys
end