如何重新设置has_many_polymorphs CRUD参数

时间:2009-06-14 22:21:34

标签: ruby-on-rails activerecord plugins polymorphism

使用has_ many_ polymorphs ActiveRecord插件处理双面多态关系的简单示例。我有两个班,“猫”和“狗”,可以互相“友谊”,所以共有三个类:“猫”,“狗”和“友谊”。猫可以和狗一起成为朋友(是的,确实发生了!)当然还有其他猫。狗也一样。这是我的模特:

class Cat < ActiveRecord::Base 
  validates_presence_of :name
end

class Dog < ActiveRecord::Base 
  validates_presence_of :name
end

class Friendship < ActiveRecord::Base
  belongs_to :left, :polymorphic => true
  belongs_to :right, :polymorphic => true

  acts_as_double_polymorphic_join(
    :lefts => [:cats, :dogs],
    :rights => [:dogs, :cats]
  )
end

我一直在努力让这个工作起来,我必须错过一些明显的东西。当我尝试创造一种新的友谊时,我得到了:

NameError (wrong constant name cats):
   (eval):7:in `before_save'
app/controllers/friendships_controller.rb:45:in `create'

NameError (wrong constant name dogs):
   (eval):7:in `before_save'
app/controllers/friendships_controller.rb:45:in `create'

这是我的schema.rb:

ActiveRecord::Schema.define(:version => 20090613051350) do
  create_table "cats", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
  create_table "dogs", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
  create_table "friendships", :force => true do |t|
    t.integer  "left_id"
    t.string   "left_type"
    t.integer  "right_id"
    t.string   "right_type"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end

我正在尝试通过POST来创建一个新的“友谊”,例如,/ cats / 3 /关系路由从URL获取left_ type和left_ id以及从中获取right_ type和right_ id POST参数。路由正确触发friendships_ controller的#create方法,结果参数如下所示:

Parameters: {
  "authenticity_token"=>"gG1eh2dXTuRPfPJ5eNapeDqJu7UJ5mFC/M5gJK23MB4=", 
  "left_type"=>"cats", 
  "right_type"=>"dogs",
  "left_id"=>"3", 
  "right_id"=>"1"
}

由于超出这个问题范围的原因,我希望将“左派”和“权利”分开,以便我可以跟踪友谊被张贴的对象(因此“左派”和“权利” “),但也许我的模型不是完成这个的正确方法?我是否误解了has_ many_ polymorphs插件的用途?这是来自friendships_ controller的#create动作:

def create
  @friendship= Friendship.new(
    :left_type => params[:left_type],
    :left_id => params[:left_id],
    :right_type => params[:right_type],
    :right_id => params[:right_id]
  )
  respond_to do |format|
    if @friendship.save
      format.xml  { 
        render :xml => @friendship, 
        :status => :created, 
        :location => @friendship
      }
    else
      format.xml  { 
        render :xml => @friendship.errors, 
        :status => :unprocessable_entity 
      }
    end
  end
end

最后我的routes.rb:

map.resources :friendships

map.resources :cats do |cat|
  cat.resources :friendships, :path_prefix => "/:left_type/:left_id"
end

map.resources :dogs do |dog|
  dog.resources :friendships, :path_prefix => "/:left_type/:left_id"
end

就像我说的那样,我花了很长时间独自尝试解决这个问题,但存在的文档要么过时,要么过于笼统,要么过于高级 - 或者在某些情况下,这三个文件同时存在。我可以告诉你,开始使用这个RoR并不容易!我知道RoR熟练程度有一些真正的好处,所以我会坚持下去,但是这些头脑中的一些人非常糟糕,我开始得到一个光头补丁。我知道有很多经验丰富的Ruby / Rails开发人员,我希望有人可以从木工中走出来,并在这里解释这件事对我们来说只是凡人。

提前致谢,

JS

2 个答案:

答案 0 :(得分:0)

我可能会选择Cat and Dog模型,然后使用has_and_belongs_to_many关联?

class Cat < ActiveRecord::Base
  has_and_belongs_to_many :dogs
end

class Dog < ActiveRecord::Base
  has_and_belongs_to_many :cats
end

然后连接表看起来像这样......

create_table "cats_dogs", :id => false, :force => true do |t|
  t.integer  "cat_id"
  t.integer  "dog_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

你可以打电话给cat.dogs和dog.cats找到任何'友谊'。

答案 1 :(得分:0)

多态关系应该能够满足您的需要,尽管如果您的猫和狗是猪的朋友,并且您想知道是谁发起了这种友谊,我以前的解决方案太简单了。

class Animal < ActiveRecord::Base
  belongs_to :creatures, :polymorphic => true
  named_scope :cats, :conditions => {:creature_type => 'Cat'}
  named_scope :dogs, :conditions => {:creature_type => 'Dog'}
  named_scope :pigs, :conditions => {:creature_type => 'Pig'}
end

class Cat < ActiveRecord::Base
  has_many :friends, :as => :creatures
end

class Dog < ActiveRecord::Base
  has_many :friends, :as => :creatures
end

class Pig < ActiveRecord::Base
  has_many :friends, :as => :creatures
end

这可能不是你想要的,但它可以让你打电话给cat.friends和cat.friends.dogs,cat.friends.pigs等。

您可以添加has_many个关联,以便直接调用cat.dogs和cat.pigs。

class Cat < ActiveRecord::Base
  has_many :friends, :as => :creatures
  has_many :dogs, :through => :animal
  has_many :pigs, :through => :animal
end

我不确定这是不是你想要的,但我认为这是一种更简单的方法,简单总是更好。