我正在使用jQuery Tokeninput,如Railscast所示。我想以嵌套的形式组合这个功能,但得到错误
undefined method `artists' for #<SimpleForm::FormBuilder:0x007febe0883988>
由于某种原因,它无法识别我的表单构建器中的track参数,这阻止了我记录下的相册。
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.artists.map(&:attributes).to_json} %>
</div>
请注意,这可以在我的track
表单中使用,但从嵌套后的album
表单中找不到。我该怎么做才能让它发挥作用?
class ArtistsController < ApplicationController
def index
@artists = Artist.order(:name)
respond_to do |format|
format.html
format.json {render json: @artists.tokens(params[:q])}
end
end
end
模型
class Artist < ActiveRecord::Base
has_many :album_ownerships
has_many :albums, through: :album_ownerships
has_many :featured_artists
has_many :tracks, through: :featured_artists
def self.tokens(query)
artists = where("name like ?", "%#{query}%")
if artists.empty?
[{id: "<<<#{query}>>>", name: "Add New Artist: \"#{query}\""}]
else
artists
end
end
def self.ids_from_tokens(tokens)
tokens.gsub!(/<<<(.+?)>>>/) {create!(name: $1).id}
tokens.split(',')
end
end
class Albums < ActiveRecord::Base
attr_reader :artist_tokens
accepts_nested_attributes_for :tracks, :reject_if => :all_blank, :allow_destroy => true
has_many :albums_ownerships
has_many :artists, through: :albums_ownerships
def artist_tokens=(ids)
self.artist_ids = Artist.ids_from_tokens(ids)
end
end
class Track < ActiveRecord::Base
attr_reader :artist_tokens
belongs_to :album
has_many :featured_artists
has_many :artists, through: :featured_artists
def artist_tokens=(ids)
self.artist_ids = Artist.ids_from_tokens(ids)
end
end
class AlbumOwnership < ActiveRecord::Base
belongs_to :artist
belongs_to :album
end
class FeaturedArtist < ActiveRecord::Base
belongs_to :artist
belongs_to :track
end
相册表格
<%= simple_form_for(@album) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<h1>Tracks</h1>
<%= f.simple_fields_for :tracks do |track| %>
<%= render 'track_fields', :f => track %>
<% end %>
<div id='links'>
<%= link_to_add_association 'Add Field', f, :tracks %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
跟踪部分
<div class="field">
<%= f.input :name %><br>
</div>
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.artists.map(&:attributes).to_json} %>
</div>
JS
$(function() {
$('#track_artist_tokens').tokenInput('/artists.json', {
prePopulate: $("#track_artist_tokens").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
});
更新
如nathanvda所述,我需要使用f.object
才能识别艺术家。所以在我的部分我现在有:
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.object.artists.map(&:attributes).to_json, class: 'test_class'} %>
在我的js中,我还需要在插入之前/之后调用令牌输入法:
$(function() {
$('.test_class').tokenInput('/artists.json', {
prePopulate: $(".test_class").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
$('form').bind('cocoon:after-insert', function(e, inserted_item) {
inserted_item.find('.test_class').tokenInput('/artists.json', {
prePopulate: $(".test_class").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
});
});
我唯一剩下的问题是tracks_attributes
没有被保存。我在过去post遇到了与此类似的问题,但两个主要区别是涉及的第二级嵌套,我在嵌套表单中使用了连接表。我不完全确定这些代码是否或如何转换,但我相信这很可能是问题所在。至于我albums_controller
允许的参数,这就是它们的样子。
def album_params
params.require(:album).permit(:name, :artist_tokens, tracks_attributes: [:id, :name, :_destroy, :track_id])
end
答案 0 :(得分:1)
如果您需要访问表单的对象,则需要编写f.object
,因此我认为您应该只写f.object.artists
。
答案 1 :(得分:0)
您的"data-pre" => f.artists...
正在artists
上调用f
方法,该方法是表单构建器,并且没有#artists
方法。
请改为尝试:
在相册表单中,将渲染部分行更改为:
<%= render 'track_fields', :f => track, :artists => @artists %>
然后在轨道部分中使用它:
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => artists.map(&:attributes).to_json} %>
已更新
让我们退一步吧。在您的代码中,您似乎需要使用data-pre
集合的属性填充artists
属性。
问题是您正在调用f.artists
,其中f
是FormBuilder,并且对artists
一无所知。这就是你得到undefined method 'artists'...
解决方案是为视图及其部分提供一系列艺术家。一种方法:
class AlbumsController < ApplicationController
...
def new
@album = Album.new
@artists = Artist.order(:name) # or some other subset of artists
end
...
def edit
@album = Album.find params[:id]
@artists = Artist.order(:name) # or perhaps "@artists = @album.artists", or some other subset of artists
end
end
然后在new.html.erb
和edit.html.erb
中,将@artists传递给表单partial:
... # other view code
<%= render 'form', album: @album %>
... # other view code
然后以你的形式部分:
... # other view code
<%= f.simple_fields_for :tracks do |track_form| %>
<%= render 'track_fields', :f => track_form %>
<% end %>
... # other view code
最后,在你的音轨部分:
... # other view code
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => @artists.map(&:attributes).to_json} %>
</div>
... # other view code
这有意义吗?