1
class User < ActiveRecord::Base
  has_one :location, :dependent => :destroy, :as => :locatable
  has_one :ideal_location, :dependent => :destroy, :as => :locatable
  has_one :birthplace, :dependent => :destroy, :as => :locatable
end

class Location < ActiveRecord::Base
  belongs_to :locatable, :polymorphic => true
end

class IdealLocation < ActiveRecord::Base
end

class Birthplace < ActiveRecord::Base
end

この状況でサブクラスを持つ理由が本当にわかりません。位置オブジェクトの動作は同じです。それらの唯一のポイントは、関連付けを簡単にすることです。また、データベースのインデックスを小さくできるため、データを文字列ではなく int として保存することをお勧めします。

私は次のようなものを想像していますが、考えを完成させることはできません:

class User < ActiveRecord::Base
  LOCATION_TYPES = { :location => 1, :ideal_location => 2, :birthplace => 3 }

  has_one :location, :conditions => ["type = ?", LOCATION_TYPES[:location]], :dependent => :destroy, :as => :locatable
  has_one :ideal_location, :conditions => ["type = ?", LOCATION_TYPES[:ideal_location]], :dependent => :destroy, :as => :locatable
  has_one :birthplace, :conditions => ["type = ?", LOCATION_TYPES[:birthplace]], :dependent => :destroy, :as => :locatable
end

class Location < ActiveRecord::Base
  belongs_to :locatable, :polymorphic => true
end

このコードでは、次のことが失敗し、基本的に役に立たなくなります。

user = User.first
location = user.build_location
location.city = "Cincinnati"
location.state = "Ohio"
location.save!

location.type # => nil

has_one 宣言の :conditions オプションを 1 に等しい型に変換する方法がないため、これは明らかです。

これらのフィールドが表示されるビューのどこにでもIDを埋め込むことができますが、これも間違っているようです:

<%= f.hidden_field :type, LOCATION_TYPES[:location] %>

余分なサブクラスを回避したり、LOCATION_TYPES アプローチを機能させる方法はありますか?

私たちの特定のケースでは、アプリケーションは非常に位置を認識しており、オブジェクトはさまざまな種類の位置を持つことができます。これらすべてのサブクラスを必要としないのは奇妙ですか?

あなたが持っている提案は大歓迎です.もしあなたが望むなら私は狂っていると言ってください.しかし、あなたはアプリ/モデルの周りに浮かぶ10以上の異なる位置モデルを見たいですか?

4

5 に答える 5

2

named_scopes を使用しないのはなぜですか?

何かのようなもの:

class User
  has_many :locations
end

class Location
  named_scope :ideal, :conditions => "type = 'ideal'"
  named_scope :birthplace, :conditions => "type = 'birthplace" # or whatever
end

次に、コードで:

user.locations.ideal => # list of ideal locations
user.locations.birthplace => # list of birthplace locations

作成時にタイプを設定する必要があると思います。

于 2010-02-18T05:33:58.780 に答える
1

私が見る限り、場所は場所です。あなたが参照しているさまざまな「サブクラス」(IdealLocation、Birthplace)は、特定のユーザーとの場所の関係を説明しているようです。その部分が間違っていたらやめてください。

それを知っていると、これに対する 2 つの解決策が見えてきます。

1 つ目は、場所をエンティティではなく値オブジェクトとして扱うことです。(用語の詳細については、値とエンティティ オブジェクト (ドメイン駆動設計)を比較してください)。上記の例では、データベースから「Cincinnati, OH」オブジェクトを見つけるのではなく、場所を「Cincinnati, OH」に設定しているようです。その場合、多数の異なるユーザーがシンシナティに存在する場合、オハイオ州シンシナティは 1 つしかありませんが、データベースには同じ "オハイオ州シンシナティ" の場所が多数存在します。私にとって、これは、エンティティではなく値オブジェクトを操作していることを明確に示しています。

このソリューションはどのように見えますか? 次のような単純な Location オブジェクトを使用する可能性があります。

class Location
  attr_accessor :city, :state

  def initialize(options={})
    @city = options[:city]
    @state = options[:state]
  end
end

class User < ActiveRecord::Base
  serialize :location
  serialize :ideal_location
  serialize :birthplace
end

@user.ideal_location = Location.new(:city => "Cincinnati", :state => "OH")
@user.birthplace = Location.new(:city => "Detroit", :state => "MI")
@user.save!

@user.ideal_location.state # => "OH"

私が見ることができる他の解決策は、既存の Location ActiveRecord モデルを使用することですが、次のように User との関係を使用して関係の「タイプ」を定義するだけです。

class User < ActiveRecord::Base
  belongs_to :location, :dependent => :destroy
  belongs_to :ideal_location, :class_name => "Location", :dependent => :destroy
  belongs_to :birthplace, :class_name => "Location", :dependent => :destroy
end

class Location < ActiveRecord::Base
end

これを機能させるために必要なことは、ユーザー モデルに location_id、ideal_location_id、およびbirthplace_id 属性を含めることだけです。

于 2010-02-18T17:22:16.037 に答える
0

before_save フックを追加してみてください

class Location
  def before_save
    self.type = 1
  end
end

他のタイプの場所についても同様です

于 2010-02-18T02:50:25.920 に答える
0

モジュールを使用して Location オブジェクトの動作をカプセル化し、いくつかのマクロを使用して関係を作成できます。

has_one <location_class>,: conditions => [ "type =?" LOCATION_TYPES [: location]],: dependent =>: destroy,: as =>: locatable

モジュールで次のようなものを使用できます。

module Orders
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def some_class_method(param)
    end

    def some_other_class_method(param)
    end

    module InstanceMethods
      def some_instance_method
      end
    end
  end
end

Rails ガイド: add-an-acts-as-method-to-active-record

于 2010-02-18T02:51:55.880 に答える
0

ここで何か重要なことを見逃しているかもしれませんが、関係に次のような名前を付けることができると思いました:

class User < ActiveRecord::Base

  has_one :location, :dependent => :destroy
  #ideal_location_id
  has_one :ideal_location, :class_name => "Location", :dependent => :destroy
  #birthplace_id
  has_one :birthplace, :class_name => "Location", :dependent => :destroy

end

class Location < ActiveRecord::Base
  belongs_to :user # user_id
end
于 2010-02-18T20:15:25.873 に答える