2014-12-01 5 views
0

Я использую jQuery Tokeninput, как показано в этом документе Railscast. Я хотел бы объединить эти функции в вложенной форме, но получает ошибкуИспользование jQuery Tokeninput в частичной вложенной форме

undefined method `artists' for #<SimpleForm::FormBuilder:0x007febe0883988> 

По какой-то причине его не признающий параметра следа в моей форме строителе, который мешает мне ухватить альбомы у меня есть на записи ,

<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 
    }); 
}); 

UPDATE

Как отметил 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 

ответ

1

Если вам нужно войти в дополнительный объект формы, вам необходимо написать f.object, поэтому, я думаю, вам стоит просто написать f.object.artists.

+0

Не могли бы вы узнать, где я это положил? Прямо сейчас у меня это в части "_track_fields", но получаю ошибку: 'uninitialized constant Track :: FeaturedArtist' с этим кодом:' <% = f.input: artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.object.artists.map (&: attributes) .to_json}%> ' –

+0

В вашей модели вы пишете, что художники связаны через признанных художников, и это модель, которая не найдена. Можете ли вы проверить, что track.artists работает вообще? Вы также не использовали определение для featured_artists. – nathanvda

+0

К сожалению, нет. Я получаю ошибку: 'undefined local variable или method 'track' для # <# : 0x007fdd97832d28>'. 'FeaturedArtist' служит только как таблица соединений между' artist' и 'tracks'. –

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 в виде частичной:

... # 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 

Это имеет смысл?

+0

С этим я получил: 'undefined method 'map' для nil: NilClass' –

+0

Вы указали действие' index' для контроллера, но затем некоторый код вашего вида использует '@ album', который не установлен в 'index'. Является ли проблема в 'new.html.erb' или' index.html.erb'? В любом случае соответствующему действию контроллера нужно будет установить как '@ художников' (как вы делали в действии' index'), так и '@ album'. Если это не поможет, можете ли вы опубликовать действие контроллера и соответствующее представление, чтобы я мог взглянуть на оба? – John

+0

Проблема технически в моих альбомах '_form.html.erb', которая отображается внутри моих« новых »и« правых »представлений. Причина, по которой я опубликовал действие «нового» художника, состояла в том, чтобы показать, как был извлечен json для функции токена jquery. Я мог бы разместить остальные контроллеры, но ни один из них не был изменен, если они были созданы с помощью эшафота (не уверен, что это поможет вам или нет). Вы рекомендуете настраивать переменную '@ albums' в одном из контроллеров? –

Смежные вопросы