Rails has_many: through и настройка свойства в модели Join - PullRequest
9 голосов
/ 21 июня 2010

Аналогично этому вопросу , как мне установить свойство в модели соединения непосредственно перед сохранением в этом контексте?

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 делает его таким, что вы можете иметь много-много связей с контекстом между ними в модели соединения. И это добавляет вспомогательные методы. Основные тесты в основном показывают, что я пытаюсь сделать. Есть лучшие идеи о том, как сделать это правильно?

1 Ответ

1 голос
/ 21 июня 2010

Посмотрите на параметры has_many в ActiveRecord :: Ассоциации :: ClassMethods API, расположенные здесь: http://rails.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001316

Это самая интересная цитата:

: условия

Укажите условия, которым должен соответствовать связанный объект, чтобы быть включенным в качестве фрагмента SQL WHERE, например, Authorized = 1. Создание записи из ассоциации ограничивается областью применения, если используется хеш. has_many: posts,: условие => {: опубликовано => 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) и объект актива в базе данных в одной атомарной транзакции.

...