Podczas korzystania z shallow routes, różne trasy wymagają innej formy argumentów
Używam tutaj prostej formy, ale jest to problem z normalnymi formami Rails. Podczas korzystania z shallow routes, formula_for potrzebuje różnych argumentów w zależności od tego, w jakim kontekście jest używany.
Przykład: do edycji (http://localhost:3000/notes/2/edit
), _form.html.erb musi mieć simple_form_for(@note)
. Ale do tworzenia nowej notki (http://localhost:3000/customers/2/notes/new
) _form.html.erb potrzebuje simple_form_for([@customer, @note])
. Jeśli któryś z nich otrzyma błędne argumenty, otrzymam metodę nie znaleziono błędu.
Jaki jest najlepszy sposób, aby sobie z tym poradzić?
- mógłbym zrobić dwa oddzielne formularze, ale to wygląda na bałagan.
- muszę ustawić @customer dla linku zwrotnego, ale mogę użyć innej zmiennej w formularzu (powiedzmy @customer_form) i po prostu nie ustawiać jej w metodzie Edytuj i aktualizuj, ale to jest niespójne i nieco mylące, ponieważ musiałbym ustawić zarówno @customer_form, jak i @customer w nowej metodzie. Mógłbym zrobić to, co zrobił ten facet i podzielić formularz na wiele plików. Wygląda na to, że najlepsza opcja jak na razie, ale nie podoba mi się to dużo, ponieważ nie można po prostu otworzyć _form.html.erb i zobacz, co się dzieje.
Przykład:
Config / routes.rb
Billing::Application.routes.draw do
resources :customers, :shallow => true do
resources :notes
end
end
Trasy Grabie | grep Uwaga
customer_notes GET /customers/:customer_id/notes(.:format) notes#index
POST /customers/:customer_id/notes(.:format) notes#create
new_customer_note GET /customers/:customer_id/notes/new(.:format) notes#new
edit_note GET /notes/:id/edit(.:format) notes#edit
note GET /notes/:id(.:format) notes#show
PUT /notes/:id(.:format) notes#update
DELETE /notes/:id(.:format) notes#destroy
App / views / notes / _form.html.erb
# v----------------------------- Right here
<%= simple_form_for (@note), html: { class: 'form-vertical'} do |f| %>
<%= f.input :content %>
<%= f.button :submit %>
<% end -%>
App / views / notes / new.html.erb
<h1>New note</h1>
<%= render 'form' %>
<%= link_to 'Back', customer_path(@customer) %>
App / views / notes / edit.html.erb
<h1>Editing note</h1>
<%= render 'form' %>
<%= link_to 'Show', @note %>
<%= link_to 'Back', customer_path(@customer) %>
App / controllers / notes_controller.rb
class NotesController < ApplicationController
def show
@note = Note.find(params[:id])
@customer = Customer.find(@note.customer_id)
respond_to do |format|
format.html
format.json {render json: @note }
end
end
# GET /notes/new
# GET /notes/new.json
def new
@note = Note.new
@customer = Customer.find(params[:customer_id])
respond_to do |format|
format.html # new.html.erb
format.json { render json: @note }
end
end
# GET /notes/1/edit
def edit
@note = Note.find(params[:id])
@customer = Customer.find(@note.customer_id)
end
# POST /notes
# POST /notes.json
def create
@customer = Customer.find(params[:customer_id])
@note = @customer.notes.build(params[:note])
respond_to do |format|
if @note.save
format.html { redirect_to @customer, notice: 'Note was successfully created.' }
format.json { render json: @note, status: :created, location: @note }
else
format.html { render action: "new" }
format.json { render json: @note.errors, status: :unprocessable_entity }
end
end
end
# PUT /notes/1
# PUT /notes/1.json
def update
@note = Note.find(params[:id])
@customer = Customer.find(@note.customer_id)
respond_to do |format|
if @note.update_attributes(params[:note])
format.html { redirect_to @customer, notice: 'Note was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @note.errors, status: :unprocessable_entity }
end
end
end
# DELETE /notes/1
# DELETE /notes/1.json
def destroy
@note = Note.find(params[:id])
@note.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
end
3 answers
Jeśli pierwszym obiektem w tablicy, który przekazujesz konstruktorowi formularzy, jest nil
, Rails będzie wysyłał tylko do drugiego obiektu. Z tego powodu po prostu nie ustawiaj swojego @customer
obiekt w akcji edycji kontrolera . Jeśli potrzebujesz dostępu do obiektu klienta, zadzwoń do niego przez @note
.
Jeśli używasz tej samej części dla new I edit, będziesz chciał ustawić @note.customer
w nowej akcji kontrolera (@customer
nie będzie ustawiona podczas edycji).
Myślę, że tak wygląda zespół Rails / align = "left" /
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-10 00:41:18
Chciałbym zaproponować drobną modyfikację rozwiązania Jamesa:
# app/helpers/application_helper.rb
def shallow_args(parent, child)
child.try(:new_record?) ? [parent, child] : child
end
Zamiast polegać na tym, że akcja kontrolera jest nazywana "nowym" - choć prawdopodobnie będzie to w 95% przypadków-sprawdza tylko, czy dziecko jest nowym rekordem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-30 14:07:02
Oto co wymyśliłem:
App / helpers / application_helper.rb
module ApplicationHelper
# Public: Pick the correct arguments for form_for when shallow routes
# are used.
#
# parent - The Resource that has_* child
# child - The Resource that belongs_to parent.
def shallow_args(parent, child)
params[:action] == 'new' ? [parent, child] : child
end
end
App / views / notes / _form.html.erb
<%= simple_form_for shallow_args(@customer, @note), html: { class: 'form-vertical'} do |f| %>
<%= f.input :content %>
<%= f.button :submit %>
<% end -%>
Nie wiem, czy to najlepsze rozwiązanie, ale wydaje się, że działa dobrze.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-19 16:51:39