我有一个看起来像这样的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
检索featured_songs非常有效。这里的问题是我无法向艺术家添加新的feature_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
,这是真正的问题。
答案 0 :(得分:2)
我在阅读完这篇文章后找到了工作解决方案:
https://github.com/rails/rails/issues/5178#issuecomment-4181551
诀窍是创建一个包含条件的新的一阶has_many关联,然后在 上运行has_many:through。
所以,在你的情况下,它将是:
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
答案 1 :(得分:0)
编辑:更新:releases_attributes以反映has_many关系。
杰德尔的回答是正确的。这是accepts_nested_attributes_for
解决的问题。 has_many
仅描述了一种查询记录的机制,而不是更新或创建它们。
您列出的属性正在更新的原因是因为它们是歌曲对象的一部分。您要更新的字段是特色字段,它是releases
联接表的一部分。
accepts_nested_attributes_for
是解决更新嵌套关系问题的工具。如果要在创建歌曲对象期间添加feature属性(就像在示例中那样),则需要将其添加为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
的选项中。
答案 2 :(得分:0)
允许通过关联保存的关键是为关联模型上的字段提供attr_accessible。
在这种情况下,在发布模型上添加一行:
attr_accessible :song_id, :feature_id
答案 3 :(得分:-1)
您可以在模型中使用accepts_nested_attributes_for。我首先看一下关于该主题的Railscast,然后仔细阅读documentation本身的方法
编辑:
从下面的评论中可以清楚地看出,我并不完全明白你的要求。我想你想知道如何从模型中创建和操作连接对象。当我最近需要这样做时,我有这两个模型:
class User < ActiveRecord::Base
belongs_to :address
accepts_nested_attributes_for :address
end
class Address < ActiveRecord::Base
has_one :user
end
然后我可以这样做以在用户上创建一个新地址
u = User.new
u.address.build({:city => "bozoville", :zip => "22222", ...})
u.save!
我的地址在我的用户身上并且仍然存在。这是你在找什么?我会说,我并不完全有效地将其转化为多对多关联,但我认为这将是同样的事情。也许是因为一对一依赖于单个列的外键有效,但是当它涉及与实际连接表的更复杂的关联时,它不起作用?至少你可以进一步研究这种可能性......