Rails has_many:通过和在Join模型上设置属性

时间:2010-06-21 02:13:09

标签: ruby-on-rails associations join

this question类似,如何在此上下文中保存之前在连接模型上设置属性?

class Post < ActiveRecord::Base
  has_many :post_assets
  has_many :assets, :through => :post_assets
  has_many :featured_images, :through => :post_assets, :class_name => "Asset", :source => :asset, :conditions => ['post_assets.context = ?', "featured"]

end

class PostAssets < ActiveRecord::Base
  belongs_to :post
  belongs_to :asset

  # context is so we know the scope or role
  # the join plays
  validates_presences_of :context
end

class Asset < ActiveRecord::Base
  has_many :post_assets
  has_many :posts, :through => :post_assets
end

我只是希望能够做到这一点:

@post = Post.create!(:title => "A Post")
@post.featured_images << Asset.create!(:title => "An Asset")
# ...
@post = Post.first
@featured = @post.featured_images.first
  #=> #<Asset id: 1, title: "An Asset">
@featured.current_post_asset #=> #<PostAsset id: 1, context: "featured">

那怎么办?我一整天都在敲打着它:)。

目前发生的事情是我这样做的时候:

@post.featured_images << Asset.create!(:title => "An Asset")

然后,创建的连接模型PostAsset永远不会有机会设置context。如何设置上下文属性?它看起来像这样:

PostAsset.first #=> #<PostAsset id: 1, context: nil>

更新

我创建了一个测试gem来尝试隔离问题。有更简单的方法吗?!

这个ActsAsJoinable::Core class使得你可以在连接模型中与它们之间的上下文建立多对多的关系。它增加了辅助方法。基本的tests基本显示了我正在尝试做的事情。关于如何正确地做到这一点的任何更好的想法?

1 个答案:

答案 0 :(得分:1)

查看位于此处的ActiveRecord :: Associations :: ClassMethods API中的has_many选项:http://rails.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001316

这是最有趣的一句话:

  

<强>:条件

     

指定关联对象必须满足的条件才能作为WHERE SQL片段包含在内,例如authorized = 1.如果使用散列,则从关联开始创建记录。 has_many:posts,:conditions =&gt; {:published =&gt; true}将使用@ blog.posts.create或@ blog.posts.build创建已发布的帖子。

所以我认为你的条件必须指定为哈希值,如下所示:

class Post < ActiveRecord::Base
  has_many :post_assets
  has_many :featured_post_assets, :conditions => { :context => 'featured' }

  has_many :assets, :through => :post_assets

  has_many :featured_images, :through => :featured_post_assets,
           :class_name => "Asset", :source => :asset,
end

您还应该执行以下操作:

@post.featured_images.build(:title => "An asset")

而不是:

@post.featured_images << Asset.create!(:title => "An Asset")

这应该调用作用域资产构建,如上面引用中所建议的那样,将上下文字段添加到资产。它还将在一个原子事务中同时将连接模型对象(post_asset)和资产对象保存到数据库中。