Rendering parziale da un altro modello
-
21-09-2019 - |
Domanda
Ho un'applicazione rotaie che modelli una casa. C'è un modello di casa che ha molti parametri e has_many rooms
. Una camera ha un house_id
e un nome. Ho anche usato http://github.com/ryanb/complex-form-examples per consentire molte luci e small_appliances
da aggiungere alla stanza. complesso forma-esempio utilizza RJS e parziali per raggiungere questo.
C'è un controller chiamato calcolatrice che è ciò che gli utenti potranno utilizzare per accedere all'applicazione. Quando si preme il pulsante di invio sul calcolatore, che reindirizza a una pagina add_rooms
(che si trova in app/views/calculator/add_rooms.html.erb
) pagina in cui l'utente può add rooms
alla casa. La pagina add_rooms utilizza un parziale app/views/rooms/_room_form.html.erb
. Non sono stato in grado di ottenere questo per visualizzare, come Rails è sempre alla ricerca di cose nella cartella app / views / calcolatrice.
Come posso ottenere questo per visualizzare? Si noti inoltre che è necessario per salvare id della casa quando si salva la stanza.
Ecco tutto il relativo codice (spero):
Aggiornamento
Se io commento le due add_child_link
. La pagina di rendering. Tuttavia, quando si fa clic presentare ricevo un nuovo messaggio di errore:
ActiveRecord::AssociationTypeMismatch in CalculatorController#add_room SmallAppliance(#49096610) expected, got Array(#1560620) RAILS_ROOT: C:/Users/ryan/Downloads/react Application Trace | Framework Trace | Full Trace C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:263:in `raise_on_type_mismatch' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb:320:in `replace' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb:320:in `each' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb:320:in `replace' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations.rb:1322:in `small_appliances=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2744:in `send' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2744:in `attributes=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2740:in `each' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2740:in `attributes=' C:/InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2438:in `initialize' C:/Users/ryan/Downloads/react/app/controllers/calculator_controller.rb:31:in `new' C:/Users/ryan/Downloads/react/app/controllers/calculator_controller.rb:31:in `add_room'
Se rimuovo la parte small_application, la stessa cosa accade per la luce. Penso che abbia qualcosa a che fare con accepts_nested_attributes_for
nel modello stanza. Ho aggiunto il codice qui sotto. Ho anche aggiunto il codice house.rb troppo.
app / modelli / room.rb
class Room < ActiveRecord::Base
belongs_to :house
has_many :lights, :dependent => :destroy
has_many :small_appliances, :dependent => :destroy
validates_presence_of :name
accepts_nested_attributes_for :lights, :reject_if => lambda { |a| a.values.all?(&:blank?) }, :allow_destroy => true
accepts_nested_attributes_for :small_appliances, :reject_if => lambda { |a| a.values.all?(&:blank?) }, :allow_destroy => true
end
app / modelli / house.rb
class House < ActiveRecord::Base
has_many :rooms
# validation code not included
def add_room(room)
rooms << room
end
end
app / controllers / calculator_controller.rb
class CalculatorController < ApplicationController
def index
end
def save_house
@house = House.new(params[:house])
respond_to do |format|
if @house.save
format.html { render :action => 'add_rooms', :id => @house }
format.xml { render :xml => @house, :status => :created, :location => @house }
else
format.html { render :action => 'index' }
format.xml { render :xml => @house.errors, :status => :unprocessable_entity }
end
end
end
def add_rooms
@house = House.find(params[:id])
@rooms = Room.find_by_house_id(@house.id)
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid house #{params[:id]}")
flash[:notice] = "You must create a house before adding rooms"
redirect_to :action => 'index'
end
def add_room
@house = House.find(params[:id])
@room = Room.new(params[:room])
respond_to do |format|
if @room.save
@house.add_room(@room)
@house.save
flash[:notice] = "Room \"#...@room.name}\" was successfully added."
format.html { render :action => 'add_rooms' }
format.xml { render :xml => @room, :status => :created, :location => @room }
else
format.html { render :action => 'add_rooms' }
format.xml { render :xml => @room.errors, :status => :unprocessable_entity }
end
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid house #{params[:id]}")
flash[:notice] = "You must create a house before adding a room"
redirect_to :action => 'index'
end
def report
flash[:notice] = nil
@house = House.find(params[:id])
@rooms = Room.find_by_house_id(@house.id)
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid house #{params[:id]}")
flash[:notice] = "You must create a house before generating a report"
redirect_to :action => 'index'
end
end
app / views / calcolatore / add_rooms.html.erb
<div id="addRooms">
<p>House id is <%= @house.id %></p>
<h3>Your rooms:</h3>
<% if @house.rooms %>
<ul>
<% for room in @house.rooms %>
<li>
<%= h room.name %> has <%= h room.number_of_bulbs %>
<%= h room.wattage_of_bulbs %> watt bulbs, in use for
<%= h room.usage_hours %> hours per day.
</li>
<% end %>
</ul>
<% else %>
<p>You have not added any rooms yet</p>
<% end %>
<%= render :partial => 'rooms/room_form' %>
<br />
<%= button_to "Continue to report", :action => "report", :id => @house %>
</div>
app / views / camere / _room_
form.html.erb
<% form_for :room, :url => { :action => :add_room, :id => @house } do |form| %>
<%= form.error_messages %>
<p>
<%= form.label :name %><br />
<%= form.text_field :name %>
</p>
<h3>Lights</h3>
<% form.fields_for :lights do |light_form| %>
<%= render :partial => 'rooms/light', :locals => { :form => light_form } %>
<% end %>
<p class="addLink"><%= add_child_link "[+] Add new light", form, :lights %></p>
<h3>Small Appliances</h3>
<% form.fields_for :small_appliances do |sm_appl_form| %>
<%= render :partial => 'rooms/small_appliance', :locals => { :form => sm_appl_form } %>
<% end %>
<p class="addLink"><%= add_child_link "[+] Add new small appliance", form, :small_appliances %></p>
<p><%= form.submit "Submit" %></p>
<% end %>
application_helper.rb
module ApplicationHelper
def remove_child_link(name, form)
form.hidden_field(:_delete) + link_to_function(name, "remove_fields(this)")
end
def add_child_link(name, form, method)
fields = new_child_fields(form, method)
link_to_function(name, h("insert_fields(this, \"#{method}\", \"#{escape_javascript(fields)}\")"))
end
def new_child_fields(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :form
form_builder.fields_for(method, options[:object], :child_index => "new_#{method}") do |form|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => form })
end
end
end
Grazie,
Ryan
Soluzione
Molto strano - se si scrive <%= render :partial => 'room_form' %>
di rotaie assumerà che è app/views/calculator/_room_form.html.erb
, ma in caso di <% = render: partial => 'camere / room_form' %> si assumerà che è app/views/rooms/_room_form.html.erb
Guarda il registro - lì si vedrà che i parziali sono stati resi
Altri suggerimenti
So che questa domanda è vecchio, ma ho incontrato lo stesso problema e sono riuscito a risolverlo.
Per essere precisi troppo stavo seguendo Ryan Bates forme complesse esempi.
La mia forma non è stato eseguito il rendering con lo stesso errore:
undefined method `reflect_on_association' for NilClass:Class
ho commentato l'aiutante add_child_link e il modulo di reso, ma al momento della presentazione ho ottenuto:
ChildModel expected, got Array
Dopo molte headscratching ho fatto un semplice cambiamento che risolto tutto:
-- form_for :project
++ form_for @project
E 'vero, solo il passaggio il simbolo di una variabile di istanza ha reso tutto il lavoro.
Spero che questo aiuti chiunque altro che si blocca
Il problema è che non si dispone di un oggetto room
definito quando si sta cercando di aggiungere un collegamento bambino.
render :partial => 'rooms/room_form', :object => Room.new