Problem z form_for dla asocjacji belongs_to

Witam
Mam spory problem z zapisaniem wartosci z formularza, którego model odnosi się do asocjacji belongs_to. To tak bardziej dla zobrazowania :slight_smile:
Mam dwa modele:

class Machine < ActiveRecord::Base
has_many :machine_notes
end

class MachineNote < ActiveRecord::Base
    belongs_to :machine
end

Do tego mam kontrolery machine_notes_controller.rb i machines_controller.rb

W widoku kontrolera machines_controller dla akcji show mam link do dodania notatki (machine_notes)

<%= link_to "Dodaj nową notatkę do maszyny", new_machine_note_path, class: "btn btn-success" %>

Następnie po przejściu do widoku new mam formularz:

<%= form_for [@machine, @machine_note] do |f| %>
<div class="form-group">
    <%= f.label :title, "Tytuł notatki" %>
    <%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
    <%= f.label :body, "Treść notatki" %>
    <%= f.text_field :body, class: "form-control" %>
</div>
<%= f.submit "Dodaj maszynę", class: "btn btn-primary" %>
<br>
<%= link_to "Anuluj", machines_path, class: "btn btn-danger" %>
<% end %>

W kontrolerze dla tego formularza mam:

def create
    @machine = Machine.find(params[:machine_id])
    @machine_note = @machine.machine_notes.new(machine_note_params)
        
    if @machine_note.save
      flash[:notice] = "Notatka dodana pomyślnie"
      redirect_to machines_path
    end
  end

private
  def machine_note_params
    params.require(:machine_note).permit(:machine_id, :title, :body)
  end

Niestety po próbie zapisania “notatki” wyskakuje błąd Couldn’t find Machine with ‘id’=

Dodam jeszcze, że w rootsach mam dodane:

  resources :machines
  resources :machine_notes

A sama baza danych ma takie tabele:

  create_table "machine_notes", force: :cascade do |t|
    t.string   "title"
    t.text     "body"
    t.integer  "machine_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "machines", force: :cascade do |t|
    t.string   "name"
    t.string   "format_printing"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
  end

Jest ktoś w stanie pomóc i poradzić co robię źle, że kontroler nie czyta z paramsów ID? może źle go podaję? :slight_smile:

Nie analizowałem tego dokładnie ale podasz jeszcze co wypluwa rake/rails routes? I nie chcesz czasem mieć zagnieżdżonych tych resourców?
resources :machines do
resources :machine_notes
end

w sumie to jeszcze nie do końca wiem do czego służy zagnieżdżone resources :slight_smile:

a obecnie rake routes wypluwa:

machines GET    /machines(.:format)                     machines#index
                        POST   /machines(.:format)                     machines#create
            new_machine GET    /machines/new(.:format)                 machines#new
           edit_machine GET    /machines/:id/edit(.:format)            machines#edit
                machine GET    /machines/:id(.:format)                 machines#show
                        PATCH  /machines/:id(.:format)                 machines#update
                        PUT    /machines/:id(.:format)                 machines#update
                        DELETE /machines/:id(.:format)                 machines#destroy
          machine_notes GET    /machine_notes(.:format)                machine_notes#index
                        POST   /machine_notes(.:format)                machine_notes#create
       new_machine_note GET    /machine_notes/new(.:format)            machine_notes#new
      edit_machine_note GET    /machine_notes/:id/edit(.:format)       machine_notes#edit
           machine_note GET    /machine_notes/:id(.:format)            machine_notes#show
                        PATCH  /machine_notes/:id(.:format)            machine_notes#update
                        PUT    /machine_notes/:id(.:format)            machine_notes#update
                        DELETE /machine_notes/:id(.:format)            machine_notes#destroy

Pokaż jeszcze parametry. W strong paramsach masz machine_id, mimo że w cale go nie wysyłasz, jednakże nie jestem pewien czy to w tym tkwi problem.

Jeśli podajesz błąd którym rzuca Ci aplikacja staraj się podać też numer linii do której się odnosi, to znacząco ułatwia debugowanie :slight_smile:

to w samej akcji new mam takie parametry:
{“controller”=>“machine_notes”, “action”=>“new”}

ten :machine_id jest dopiero w tabeli machine_notes, a co do linii to załączam screena

na screenie widac, ze mam zakomentowane czytanie ID tej maszyny i wtedy zapisuje normalnie :slight_smile:

aha chyba nie mozna dolaczac screena… ale wskazane jest konkretnie na tą linie z params[machine_id]

    #@machine = Machine.find(38)
    @machine = Machine.find(params[:machine_id])
    @machine_note = @machine.machine_notes.new(machine_note_params)

W params nie masz parametry params[:machine_id] tylko params[:id] dlatego wyskakuje ci taki błąd

a jak mu podac params[:machine_id]? dopiero w samym formularzu?

<%= form_for @machine_note do |f| %>

nie bardzo to rozumiem, bo kolumna machine_id znajduje się w tabeli machine_notes i w tej kolumnie ma byc zapisany ID maszyny do której przypisana jest “notatka”

Jak tworzysz machne_note przez asocjacje to machine_id uzupełnia się automatycznie. rake routes pokazały ci jakie parametry uzykasz z urla, dorzuć do tego parametry które przesyłasz w formularzu i masz komplet params. Moja rada to rób krok po kroku a nie staraj się ukryźć wszystkiego na raz. Najpierw masz znaleźć Machine to szukasz machine, jak będziesz pewien że to zostało znalezione to wtedy idziesz dalej.

Bardzo dziękuję za uwagi. Faktycznie ciągle myślę w sposób taki, że od razu chcę uzyskać pełny wynik.

Co do tego, że zadziałało to dodałem zagnieżdżone resources w routes i zastosowałem się trochę do dokumentacji co do form_for

<%= form_for ([@machine, @machine_note]) do |f| %>

do tego w kontrolerze:

  def new
    @machine = Machine.find(params[:id])
    @machine_note = MachineNote.new
  end
  
  def create
    @machine = Machine.find(params[:machine_id])
    @machine_note = @machine.machine_notes.create(machine_note_params)
  
    #render text: params
    
    if @machine_note.save
      flash[:notice] = "Notatka dodana pomyślnie"
      redirect_to machines_path
    end
  end

I najważniejsze jest to, że w linku, który prowadzi do stworzenia notatki dodałem (params) i teraz mam ID maszyny do której chcę przypisać notatkę:

<%= link_to "Dodaj nową notatkę do maszyny", new_machine_note_path(params), class: "btn btn-success" %>

Pytanie tylko, czy to jest prawidłowe stosowanie się do asocjacji belongs_to i has_many, czy nie omijam pewnych konwencji, których powinienem się trzymać? Jeszcze mam problem ze zrozumieniem mechaniki rails dlatego dopytuję :slight_smile:

Z tego co wkleiłeś to nie widać że routes.rb mają zagnieżdżenie. Jakbyś miał zagnieżdżenie to <%= form_for ([@machine, @machine_note]) do |f| %> by zadziałał a tak to nie ma szans że wygeneruje ci prawidłowy adres. Kolejna sprawa, gdybyś miał zagnieżdżony zasób to nie miałbyś helpera new_machine_note_path tylko new_machine_machine_note_path. I ostatnia rzecz nie przekazuj całych params w helperach routingu tylko konkretne wartości.

Ja dodałem te zagniezdzenie dopiero pozniej:

  resources :machines do
    resources :machine_notes
  end
  
  resources :machine_notes do
    resources :machines
  end

Po tym rails rotes wygląda w taki sposob:

machine_machine_notes GET    /machines/:machine_id/machine_notes(.:format)               machine_notes#index
                      POST   /machines/:machine_id/machine_notes(.:format)               machine_notes#create
 new_machine_machine_note GET    /machines/:machine_id/machine_notes/new(.:format)           machine_notes#new
edit_machine_machine_note GET    /machines/:machine_id/machine_notes/:id/edit(.:format)      machine_notes#edit
 machine_machine_note GET    /machines/:machine_id/machine_notes/:id(.:format)           machine_notes#show
                      PATCH  /machines/:machine_id/machine_notes/:id(.:format)           machine_notes#update
                      PUT    /machines/:machine_id/machine_notes/:id(.:format)           machine_notes#update
                      DELETE /machines/:machine_id/machine_notes/:id(.:format)           machine_notes#destroy
             machines GET    /machines(.:format)                                         machines#index
                      POST   /machines(.:format)                                         machines#create
          new_machine GET    /machines/new(.:format)                                     machines#new
         edit_machine GET    /machines/:id/edit(.:format)                                machines#edit
              machine GET    /machines/:id(.:format)                                     machines#show
                      PATCH  /machines/:id(.:format)                                     machines#update
                      PUT    /machines/:id(.:format)                                     machines#update
                      DELETE /machines/:id(.:format)                                     machines#destroy
machine_note_machines GET    /machine_notes/:machine_note_id/machines(.:format)          machines#index
                      POST   /machine_notes/:machine_note_id/machines(.:format)          machines#create
 new_machine_note_machine GET    /machine_notes/:machine_note_id/machines/new(.:format)      machines#new
edit_machine_note_machine GET    /machine_notes/:machine_note_id/machines/:id/edit(.:format) machines#edit
 machine_note_machine GET    /machine_notes/:machine_note_id/machines/:id(.:format)      machines#show
                      PATCH  /machine_notes/:machine_note_id/machines/:id(.:format)      machines#update
                      PUT    /machine_notes/:machine_note_id/machines/:id(.:format)      machines#update
                      DELETE /machine_notes/:machine_note_id/machines/:id(.:format)      machines#destroy
        machine_notes GET    /machine_notes(.:format)                                    machine_notes#index
                      POST   /machine_notes(.:format)                                    machine_notes#create
     new_machine_note GET    /machine_notes/new(.:format)                                machine_notes#new
    edit_machine_note GET    /machine_notes/:id/edit(.:format)                           machine_notes#edit
         machine_note GET    /machine_notes/:id(.:format)                                machine_notes#show
                      PATCH  /machine_notes/:id(.:format)                                machine_notes#update
                      PUT    /machine_notes/:id(.:format)                                machine_notes#update
                      DELETE /machine_notes/:id(.:format)                                machine_notes#destroy

Jezeli chodzi o params to zmienilem i podaję tylko ID maszyny dla posta i faktycznie zmienilem na sciezke new_machine_machine_note:

new_machine_machine_note_path(machine_id: params[:id])

Generalnie wszystko działa poza tym, że gdy robię edycję machine_note to po zapisaniu nie potrafię wrócić do machine o danym id :confused:

Generalnie wszystko działa poza tym, że gdy robię edycję machine_note to po zapisaniu nie potrafię wrócić do machine o danym id :confused:

spróbuje zanalizować linijka po linijce akcję create i dojdziesz co jest nie tak, mała podpowiedź, chodzi o redirect_to (trzeba zmienić)

Powrót po stworzeniu machine_note działa… ustawiłem
redirect @machine

ale dla następnej akcji edit po zapisaniu nie potrafię wrócić. Ponizej mam akcje dla edit i update:

  def edit
    @machine_note = MachineNote.find(params[:id])
    
  end
  
  def update
    #render text: params
    
    @machine_note = MachineNote.find(params[:id])
    @machine_note.update_attributes(machine_note_params)
    flash[:notice] = "Notatka została zaaktualizowana"
    redirect_to machines_path
  end

Teraz redirect_to powraca do oglnej sciezki ze wszystkimi maszynami, a chcial bym wrocic do tej maszyny w której edytowałem machine_note.

Dodałem sobie tez zmienną, która odwoluje się do id maszyny:
@machine = Machine.find(params[:machine_id])
i ustawiłem
redirect_to @machine
ale niestety nie widzi :machine_id mimo, że, w paramsach jest ten machine_id
{"controller"=>"machine_notes", "action"=>"edit", "machine_id"=>"38", "id"=>"16"}

z machine_note masz asocjacje do machine

a na jakąś jeszcze podpowiedź mogę liczyć? :slight_smile: nie potrafię przekazać id do którego ma się odnieść redirect_to. Może sam form_for powinien coś jeszcze posiadać? bo po kliknięciu submit w paramsach nie ma id maszyny.

@machine_note.machine zwraca model Machine to ci powinno wystarczyć.

Działa fantastycznie :slight_smile: wielkie dzięki :slight_smile: