Domanda

I'm on Rails 4. Let's say I have three models: House, Color, and HouseColoring.

class House < ActiveRecord::Base
  has_many :house_colorings
  has_many :colors, through: :house_colorings
  accepts_nested_attributes_for :house_colorings, allow_destroy: true
end

class Color < ActiveRecord::Base
  has_many :house_colorings
  has_many :houses, through: :house_colorings
end

class HouseColoring < ActiveRecord::Base
  belongs_to :house
  belongs_to :color
end

houses_controller.rb:

class HousesController < ApplicationController
  before_action :set_house
  ...

  def new
    @house = House.new
    @house.house_colorings.build
  end

  def create
    @house = House.create(house_params)
    if @house.save
      redirect_to @house
    else
      render 'new'
    end
  end

  def edit
    #Gets @house from set_house
  end

  def update
    if @house.update(house_params)
      redirect_to @house
    else
      render 'edit'
    end
  end

  ...

  private

    def set_house
      @house = House.find(params[:id])
    end

    def house_params
      params.require(:house).permit(:some_parameters, house_colorings_attributes: [:id, :color_id])
    end
end

Here is my _form.html.erb partial for my house new and edit

<%= form_for @house do |f| %>
  <div id="house_colorings">
    <%= f.fields_for :house_colorings do |c| %>
      <%= render "house_colorings", f: c %>
    <% end %>
  <%= link_to "Add color", add_color_path, remote: true %>
</div>
<% end %>

_house_colorings.html.erb:

<%= f.collection_select :color_id, Color.all, :id, :name, {include_blank: "Select color"} %>

In the houses_controller, I've added:

def add_color
  respond_to do |format|
    format.js
  end
end

add_color.js.erb:

$("#house_colorings").append("<%= escape_javascript render 'house_colorings', f: c %>");

I added a route for my add_color method:

GET "/add_color" => "houses#add_color"

When I click my add color link, nothing happens on screen, but in my log I get a 500 internal server error.

Started GET "/add_color" for 127.0.0.1 at 2013-10-26 21:11:41 -0700
Processing by HousesController#add_color as JS
  Rendered houses/add_color.js.erb (11.3ms)
Completed 500 Internal Server Error in 14ms

ActionView::Template::Error (undefined local variable or method `f' for #<#<Class:0x007fc317428538>:0x007fc31710d060>):
    1: $("#house_colorings").append("<%= escape_javascript render 'house_colorings', f: c %>");
  app/views/houses/add_color.js.erb:1:in `_app_views_houses_add_color_js_erb__1847085463095078116_70237941180700'

As of now, I only have one field to add a house_coloring to my house. I want to add some ajax, and have a link in my form that adds a new field after the one that is there, but I'm not sure how to do this.

I've gone through the "Nested model form" from Railscasts and used parts of them to get to the point I am now, but I would like to use the "data_remote" helpers provided by rails if I can. I've edited my question and included the log for the error I'm getting when I click my add color link. I'm pretty sure that I need to change either my add_color.js.erb or the add_color action in my houses controller.

Any suggestions?

È stato utile?

Soluzione

Well, you do have couple alternatives here.

  1. Use the information in the Nested model forms railscasts: Part 1 and Part 2

  2. Use the FormObject Pattern to make thet nesting a bit easier. The pattern is described in a dozen places and also on railscasts (subscribtion needed).

  3. Use a js framework like Angular.js to add new fields on the client side on the fly. Angular.js is also covered in a railscast (subscribtion needed) and has very rich documentation.

UPDATE The error tells you pretty much all of it. You send a c object to the partial as a form-builder object. And seems like you don't instantiate it in the houses#add_color action.

Altri suggerimenti

Check out these two railscasts episode:

Nested Forms 1

Nested Forms 2

The 2nd one explains in depth what you're exactly looking for.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top