通过 has_many :through with :conditions 保存连接属性

发布于 2024-11-29 01:21:48 字数 1944 浏览 0 评论 0原文

我有一个如下所示的 Artist 模型:

# app/models/artist.rb
class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases
  has_many  :featured_songs,  :through => :releases,
                              :class_name => "Song",
                              :source => :song,
                              :conditions => { 'releases.featured', true }                         

end

检索 features_songs 效果非常好。这里的问题是我无法向艺术家添加新的featured_song,因为由于某种原因“featured”属性设置为“nil”。

这就是我正在尝试的:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)

实际结果是:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)
  User Load (0.9ms)  SELECT `users`.* FROM `users` LIMIT 1
  SQL (1.0ms)  BEGIN
  SQL (5.5ms)  INSERT INTO `songs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES (?, ?, ?, ?)  [["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["title", "Title"], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["user_id", 1]]
  SQL (1.2ms)  INSERT INTO `releases` (`album_id`, `artist_id`, `created_at`, `featured`, `song_id`, `updated_at`) VALUES (?, ?, ?, ?, ?, ?)  [["album_id", nil], ["artist_id", 1], ["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["featured", nil], ["song_id", 6], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00]]
   (0.1ms)  COMMIT

注意: ["featured", nil]

知道我做错了什么吗?如何在不直接访问连接的情况下正确设置连接属性?

谢谢你!

编辑: 为了使我的问题更清楚:

  • 从艺术家的实例中,我无法通过 featured_songs 关系创建新的精选歌曲

  • 保存似乎正在设置所有歌曲属性,除了(最重要的)featured

  • 由于某种原因,featured 属性被设置为 nil,这才是真正的问题

I have an Artist model that looks like this:

# app/models/artist.rb
class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases
  has_many  :featured_songs,  :through => :releases,
                              :class_name => "Song",
                              :source => :song,
                              :conditions => { 'releases.featured', true }                         

end

Retrieving the featured_songs works perfectly. The issue here is I'm unable to add a new featured_song to an artist because for some reason the 'featured' attribute is set to 'nil'.

This is what I'm attempting:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)

The actual result of that is:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)
  User Load (0.9ms)  SELECT `users`.* FROM `users` LIMIT 1
  SQL (1.0ms)  BEGIN
  SQL (5.5ms)  INSERT INTO `songs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES (?, ?, ?, ?)  [["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["title", "Title"], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["user_id", 1]]
  SQL (1.2ms)  INSERT INTO `releases` (`album_id`, `artist_id`, `created_at`, `featured`, `song_id`, `updated_at`) VALUES (?, ?, ?, ?, ?, ?)  [["album_id", nil], ["artist_id", 1], ["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["featured", nil], ["song_id", 6], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00]]
   (0.1ms)  COMMIT

Notice the: ["featured", nil]

Any idea what i'm doing wrong? How can i properly set attributes on my join without accessing it directly?

thank you!

EDIT:
To make my issue more clear:

  • From an instance of artist i am unable to create new featured songs through the featured_songs relationship

  • Saves appear to be setting all of the song attributes EXCEPT for (the most important one) featured

  • The featured attribute is being set to nil for some reason and this is the real issue here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜妞爱困 2024-12-06 01:21:48

我在阅读后找到了可行的解决方案:

https://github.com/rails/ Rails/issues/5178#issuecomment-4181551

技巧是创建一个包含条件的新一阶 has_many 关联,然后运行 ​​has_many :通过那个

所以,就你而言,它将是:

class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases

  has_many  :featured_releases, :class_name => "Release", :conditions => { :featured => true }
  has_many  :featured_songs, :through => :featured_releases, :source => :song
end

I found the working solution after reading this:

https://github.com/rails/rails/issues/5178#issuecomment-4181551

The trick is to create a new first-order has_many association that contains the condition, and then run the has_many :through on that.

So, in your case, it would be:

class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases

  has_many  :featured_releases, :class_name => "Release", :conditions => { :featured => true }
  has_many  :featured_songs, :through => :featured_releases, :source => :song
end
潜移默化 2024-12-06 01:21:48

编辑:更新:releases_attributes 以反映 has_many 关系。

杰德尔的回答是正确的。这是由 accepts_nested_attributes_for 解决的问题。 has_many 仅描述一种查询记录的机制,而不是更新或创建记录。

您列出的属性被更新的原因是因为它们是歌曲对象的一部分。您尝试更新的字段是特色字段,它是 releases 连接表的一部分。

accepts_nested_attributes_for是解决更新嵌套关系问题的工具。如果您想在创建歌曲对象期间添加特色属性(如您在示例中所做的那样),那么您需要将其添加为 Song 类的嵌套属性的一部分。

class Song < ActiveRecord::Base
  has_many :releases
  has_many :artists, :through => :releases
  accepts_nested_attributes_for :releases
end

您的 create 将如下所示:

a.songs.create(:title => 'Title', :user => User.first, :releases_attributes => [{ :id => 123, :featured => true}])

注意添加了 _attributes。如果您使用嵌套表单,这正是 Rails 在视图中执行的操作。请参阅 ActiveRecord 源文件 nested_attributes.rb证明。

如果您确实想要一种更简洁的方法来实现此目的,您可以添加一个 Song#create_featured 方法,该方法会将 :releases_attributes 哈希合并到 #create< 的选项中/代码>。

EDIT: Updated :releases_attributes to reflect has_many relationship.

jaydel's answer is along the right lines. This is a problem solved by accepts_nested_attributes_for. has_many only describes a mechanism to query records, not to update or create them.

The reason the attributes you listed are being updated is because they are part of the song object. The field you're trying to update is the featured field, which is part of your releases join table.

accepts_nested_attributes_for is the tool to solve the problem of updating nested relationships. If you want to add the featured attribute during creation of a song object (as you do in your example), then you need to add that as part of the nested attributes for the Song class.

class Song < ActiveRecord::Base
  has_many :releases
  has_many :artists, :through => :releases
  accepts_nested_attributes_for :releases
end

Your create would then look something like this:

a.songs.create(:title => 'Title', :user => User.first, :releases_attributes => [{ :id => 123, :featured => true}])

Note the addition of _attributes. This is exactly what Rails would do in the views if you were using nested forms. See the ActiveRecord source file nested_attributes.rb for proof.

If you really wanted a cleaner way to accomplish this, you could add a Song#create_featured method that would merge the :releases_attributes hash into the options to #create.

只是我以为 2024-12-06 01:21:48

允许通过关联保存的关键是为关联模型上的字段提供 attr_accessible 。

在这种情况下,在发布模型上添加行:

attr_accessible :song_id, :feature_id

The key to allow save through association is to provide attr_accessible to fields on association model.

In this case, add line on Release model:

attr_accessible :song_id, :feature_id
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文