【问题标题】:Rails has_many :through and Setting Property on Join modelRails has_many :through 和在 Join 模型上设置属性
【发布时间】:2011-03-06 03:16:44
【问题描述】:

类似于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 基本上显示了我正在尝试做的事情。有关如何正确执行此操作的任何更好的想法?

【问题讨论】:

  • 这似乎也与我本周早些时候的问题相似:stackoverflow.com/questions/3035064/… 我只是追溯更改了联接模型。但是,我认为必须有一个回调才能在保存连接模型之前对其进行处理。 +1 因为我很好奇。
  • 在非连接模型上有一个before_addafter_add 回调(所以在帖子上是assets),但是如果不调用@,你就无法真正访问连接模型987654335@。在阅读了所有论坛之后,它似乎是 Rails 中缺少的功能。

标签: ruby-on-rails associations join


【解决方案1】:

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

这是最有趣的一句话:

:条件

指定关联对象必须满足的条件才能被包含为 WHERE SQL 片段,例如授权 = 1。如果使用散列,则从关联中创建的记录是有范围的。 has_many :posts, :conditions => {:published => 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)和资产对象保存到数据库中。

【讨论】:

  • @post.featured_images &lt;&lt; Asset.first 和相关(实际上不是构建/创建它)呢?
  • 我很确定 build 在保存 @post 对象之前不会保存新记录。
  • 这不适用于 :through 关联。至少在 Rails 3.2.12 中没有。在通过关联指定条件时,object.association.build 不会设置这些条件。也许这是 Rails 中的一个错误,或者只是不适合使用 :through 关联。
  • 如果其他人遇到这种情况,设置条件的正确方法是在连接模型上。所以,在上面的例子中,它会变成类似 has_many :featured_post_assets, :conditions => { :context => "featured" } 的东西。然后从 :featured_images 关联中去掉条件。
  • 在 Rails4 中使用 :conditions 现在不推荐使用 lambda。我在这里问了一个与这个问题非常相似的问题:stackoverflow.com/questions/17098708/…
猜你喜欢
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2019-03-04
  • 2012-02-22
  • 2016-02-03
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多