Problem - undefined method `map' for nil:NilClass

Hej!

Mam problem w aplikacji którą staram się pisać mianowicie w select’cie któremu staram się przekazać parametry z modelu speakers - dostaje

undefined method `map’ for nil:NilClass

wskazuje na:

<%= speaker_form.select_tag "speaker[]", 
        options_from_collection_for_select(@speakers, 'id', 'speaker'), 
        class: "form-control"  %>

co odnosi się do akcji w kontrolerze

  def create
@agenda = Agenda.new(agenda_params)

speaker_ids = params[:speaker].select(&:present?)
@speakers = Speaker.where(id: speaker_ids)

@speakers.each do |speaker|
  @agenda.confdays(params[:speakers]) << speaker
end
@speaker = @agenda.confdays.first.speakers.select(&:present?)


respond_to do |format|
  if @agenda.save
    format.html { redirect_to @agenda, notice: 'Agenda was successfully created.' }
    format.json { render :show, status: :created, location: @agenda }
  else
    format.html { render :new }
    format.json { render json: @agenda.errors, status: :unprocessable_entity }
  end
end

end

czy ktoś ma pomysł jak to rozwiązać? dodam jeszcze że relacja w bazie danych jest taka że confday ma wiele speaker’ow

z góry dzięki za pomoc!

Zmienna @speakers ma wartość nil. Pokazałeś tutaj zawartość metody create w kontrolerze, tymczasem widok z tym formularzem jest renderowany najprawdopodobniej poprzez metodę new.

dzięki za podpowiedz, pokazuje w takim razie metodę new

  def new
    @agenda = Agenda.new
    @speakers = Speaker.all
    @agenda.confdays.build
  end

Najlepiej będzie, jeżeli wkleisz link do fragmentu development.log (od początku requestu), bo nie wiadomo jaka metoda jest wywoływana (najlepiej skorzystać gist.github.com, pastebin.com).

Jeszcze kilka uwag:

speaker_ids = params[:speaker].select(&:present?)

Nie ma specjalnego sensu usuwać pustych stringów z tej tablicy, ponieważ zrobi to za ciebie AR (zamieni nil na NULL a pusty string na 0). Dotyczy przypadku kiedy klucz główny jest liczbą.

@agenda.confdays(params[:speakers])

Reader asocjacji w Rails przyjmuje jeden opcjonalny parametr typu Boolean, który informuje AR, czy należy przeładować dane i najczęściej nie musisz się nim przejmować. W tym przypadku przekazanie params[:speakers] nie ma sensu (jest traktowane jako true).

@speakers.each do |speaker|
  @agenda.confdays(params[:speakers]) << speaker
end

Nie ma potrzeby dodawać relacji pojedynczo. Możesz przekazać od razu całą tablicę / listę z relacji, czyli zrobić @agenda.confdays << @speakers. Problem tylko tutaj polega na tym, że dodajesz bezpośrednio speakerów do relacji confdays, a z nazwy i następnej linijki wynika, że confdays to dni, które z kolei zawierają speakers.

@speaker = @agenda.confdays.first.speakers.select(&:present?)

Nie ma możliwości, aby któryś z elementów tej relacji był pusty (miał wartość nil lub był pustym łańcuchem). W związku z tym nie ma sensu używanie Array#select, bo zwróci Ci to te same rekordy. Efekt uboczny będzie taki, że w zmiennej zamiast relacji ActiveRecord będziesz miał Array. Dodatkowo - nazwa zmiennej @speaker sugeruje, że chcesz tam mieć jednego speakera, a tymczasem przekazujesz wszystkich z pierwszego dnia konferencji.

Jeszcze uwaga ogólna. Kiedy wykona się akcja new, to na podstawie zmiennych z definiowanych w kontrolerze zostanie zbudowany formularz, który masz w szablonie. Następnie, jeżeli po próbuje jego zapisania nastąpi błąd walidacji, to kontroler ponownie wyrenderuje Ci szablon ‘new’, ale tym razem korzystające ze zmiennych w metodzie create. Oznacza to, że @speakers, które chcesz mieć w liście wyboru będą miały w obu przypadkach z goła różne wartości. Z pewnością to nie jest to, czego się spodziewasz.

wrzuciłem aplikację na github, więc jeśli możesz rzucić okiem i coś podpowiedzieć będę bardzo wdzięczny - z góry WIELKIE dzięki! - https://github.com/rediver/HappyConf

mega cenna uwaga, poprawię to w następnym commicie, nasuwa się pytanie w jakich więc wypadkach zasadne jest korzystanie z select(&:present?)

czyli jak to powinienem prawidłowo zapisać? :wink:

anyone?

po wysłaniu formularza params[:speaker] nie istnieje. Sprawdź w konsoli jakie parametry są wysyłane i odbierane w akcji POST i uzupełnij braki lub zmodyfikuj kod.