Рендеринг частичного от другой модели

У меня есть приложение рельсов, которое моделирует дом. Существует модель дома, которая имеет много параметров, и это has_many rooms. У комнаты есть house_idимя и имя. Я также использовал http://github.com/ryanb/complex-form-examples, чтобы разрешить много источников света и small_appliancesдобавить их в комнату. complex-form-example использует RJS и партиалы для достижения этой цели.

Существует контроллер под названием калькулятор, который пользователи будут использовать для доступа к приложению. Когда кнопка отправки на калькуляторе нажата, она перенаправляет на add_roomsстраницу (расположена на app/views/calculator/add_rooms.html.erb), где пользователь может add roomsпопасть в дом. Страница add_rooms использует частичное из app/views/rooms/_room_form.html.erb. Я не смог отобразить это, так как rails всегда ищет что-то в папке app / views / calculator.

Как я могу получить это для отображения? Обратите внимание, что мне нужно сохранить идентификатор дома при сохранении комнаты.

Вот весь соответствующий код (я надеюсь):

Обновить

Если я закомментирую два add_child_link. Страница рендеринга. Однако, когда я нажимаю «Отправить», я получаю новое сообщение об ошибке:

ActiveRecord :: AssociationTypeMismatch в CalculatorController # add_room

Ожидается SmallAppliance (# 49096610), получил массив (# 1560620)

RAILS_ROOT: C: / Пользователи / Райан / Загрузки / Реакция
Трассировка приложений | Framework Trace | Полная трассировка

C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb: 263: в поднять_on_type_mismatch
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb: 320: в `replace '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb: 320: в «каждом»
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_collection.rb: 320: в `replace '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations.rb: 1322: в `small_appliances = '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb: 2744: в `send '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb: 2744: в `attribute = '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb: 2740: в "каждом"
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb: 2740: в `attribute = '
C: /InstantRails/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb: 2438: в `initialize '
C: /Users/ryan/Downloads/react/app/controllers/calculator_controller.rb: 31: в "новом"
C: /Users/ryan/Downloads/react/app/controllers/calculator_controller.rb: 31: в `add_room '

Если я удаляю часть small_application, то же самое происходит и для light. Я думаю, что это как-то связано с accepts_nested_attributes_forмоделью комнаты. Я добавил код ниже. Я также добавил код house.rb тоже.

приложение / модели / 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

приложение / модели / house.rb

class House < ActiveRecord::Base
  has_many :rooms

  # validation code not included

  def add_room(room)
    rooms << room
  end

end

приложение / контроллеры / 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

приложение / просмотров / калькулятор / 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 / rooms / _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

Спасибо
Райан

12.10.2009 21:06:05
3 ОТВЕТА
РЕШЕНИЕ

Очень странно - если вы напишите, то <%= render :partial => 'room_form' %>rails будет предполагать, что это так app/views/calculator/_room_form.html.erb, но в случае <% = render: частичный => 'rooms / room_form'%> это будет предполагать, что этоapp/views/rooms/_room_form.html.erb

Следите за своим журналом - там вы увидите, какие части были обработаны

3
10.02.2017 00:00:40
Когда я использую render :partial => 'rooms/room_form', я получаю эту ошибку: Отображение app / views / rooms / _room_form.html.erb, где поднята строка # 13: неопределенный метод 'refle_on_association' для NilClass: Class Это происходит из вызова add_child_link. Я добавил application_helper.rb в исходное сообщение.
Ryan 13.10.2009 01:24:20

Проблема в том, что у вас нет определенного roomобъекта, когда вы пытаетесь добавить дочернюю ссылку.

render :partial => 'rooms/room_form', :object => Room.new
0
13.10.2009 02:09:27

Я знаю, что этот вопрос старый, но я столкнулся с той же проблемой и сумел ее решить.

Чтобы быть точным, я тоже следовал примеру сложных форм Райана Бейтса.

Моя форма не рендерилась с той же ошибкой:

undefined method `reflect_on_association' for NilClass:Class

Я закомментировал помощника add_child_link и визуализированную форму, но после отправки я получил:

ChildModel expected, got Array

После долгих раздумий я сделал одно простое изменение, которое исправило все:

-- form_for :project
++ form_for @project

Это верно, просто переключение символа для переменной экземпляра заставило все это работать.

Надеюсь, это поможет любому, кто застрянет

1
13.07.2010 16:59:53