Ruby on rails 轨道中的动态形式,命名为

Ruby on rails 轨道中的动态形式,命名为,ruby-on-rails,nomethoderror,railscasts,dynamic-forms,Ruby On Rails,Nomethoderror,Railscasts,Dynamic Forms,我是rails的新手,当时我正在根据这个railscast建造一些东西 由于这是非常过时的,我无法下载它所依赖的一个旧gem-至少,使用RVM-所以我无法真正检查它 然而,有人将它从rails 3更新到了4.2,但是我一直得到一个未定义的方法'fields',用于nil:NilClass错误 Product.rb class Product < ActiveRecord::Base belongs_to :product_type serialize :properties, H

我是rails的新手,当时我正在根据这个railscast建造一些东西

由于这是非常过时的,我无法下载它所依赖的一个旧gem-至少,使用RVM-所以我无法真正检查它

然而,有人将它从rails 3更新到了4.2,但是我一直得到一个未定义的方法'fields',用于nil:NilClass错误

Product.rb

class Product < ActiveRecord::Base
  belongs_to :product_type
  serialize :properties, Hash

 validate :validate_properties

 def validate_properties
   product_type.fields.each do |field|
    if field.required? && properties[field.name].blank?
     errors.add field.name, "must not be blank"
    end
  end
 end
end
class ProductTypesController < ApplicationController

 def index
  @product_types = ProductType.all

   respond_to do |format|
     format.html 
     format.json { render json: @product_types }
   end
 end


 def show
   @product_type = ProductType.find(params[:id])

   respond_to do |format|
     format.html 
     format.json { render json: @product_type }
   end
 end


 def new
   @product_type = ProductType.new

   respond_to do |format|
    format.html 
    format.json { render json: @product_type }
   end
  end

 def edit
  @product_type = ProductType.find(params[:id])
 end


 def create
  @product_type = ProductType.new(product_type_params)

  respond_to do |format|
    if @product_type.save
      format.html { redirect_to @product_type, notice: 'Product type was    successfully created.' }
    format.json { render json: @product_type, status: :created, location: @product_type }
    else
    format.html { render action: "new" }
    format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
  end


def update
  @product_type = ProductType.find(params[:id])

  respond_to do |format|
    if @product_type.update_attributes(product_type_params)
      format.html { redirect_to @product_type, notice: 'Product type was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
 end


def destroy
  @product_type = ProductType.find(params[:id])
  @product_type.destroy

  respond_to do |format|
    format.html { redirect_to product_types_url }
    format.json { head :no_content }
  end
 end

 def product_type_params
   params.require(:product_type).permit(
        :name, fields_attributes: [ :field_type, :name, :required ] )
 end
end
class ProductsController < ApplicationController
      def index
        @products = Product.all
      end

      def show
        @product = Product.find(params[:id])
      end

      def new
        @product = Product.new(product_type_id: params[:product_type_id])
      end

      def edit
        @product = Product.find(params[:id])
      end

      def create
        @product = Product.new(product_params)
        if @product.save
          redirect_to @product, notice: 'Product was successfully created.'
        else
          render action: "new"
        end
      end

      def update
        @product = Product.find(params[:id])
        if @product.update_attributes(product_params)
          redirect_to @product, notice: 'Product was successfully updated.'
        else
          render action: "edit"
        end
      end

      def destroy
        @product = Product.find(params[:id])
        @product.destroy
        redirect_to products_url
      end

      private

      def product_params
        params.require(:product).permit(:name, :price, :product_type_id,
                                    :properties)
      end
    end
<%= form_for @product do |f| %>
      <% if @product.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>
          <ul>
          <% @product.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <%= f.hidden_field :product_type_id %>

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name %>
      </div>
      <div class="field">
        <%= f.label :price %><br />
        <%= f.text_field :price %>
      </div>

      <%= f.fields_for :properties, OpenStruct.new(@product.properties) do |builder| %>
        <% @product.product_type.fields.each do |field| %>
          <%= render "products/fields/#{field.field_type}", field: field, f: builder %>
        <% end %>
      <% end %>

      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>
Product_field.rb-Rails 4.2

class ProductField < ActiveRecord::Base
 belongs_to :product_type
end
class ProductField
产品类型\u控制器.rb

class Product < ActiveRecord::Base
  belongs_to :product_type
  serialize :properties, Hash

 validate :validate_properties

 def validate_properties
   product_type.fields.each do |field|
    if field.required? && properties[field.name].blank?
     errors.add field.name, "must not be blank"
    end
  end
 end
end
class ProductTypesController < ApplicationController

 def index
  @product_types = ProductType.all

   respond_to do |format|
     format.html 
     format.json { render json: @product_types }
   end
 end


 def show
   @product_type = ProductType.find(params[:id])

   respond_to do |format|
     format.html 
     format.json { render json: @product_type }
   end
 end


 def new
   @product_type = ProductType.new

   respond_to do |format|
    format.html 
    format.json { render json: @product_type }
   end
  end

 def edit
  @product_type = ProductType.find(params[:id])
 end


 def create
  @product_type = ProductType.new(product_type_params)

  respond_to do |format|
    if @product_type.save
      format.html { redirect_to @product_type, notice: 'Product type was    successfully created.' }
    format.json { render json: @product_type, status: :created, location: @product_type }
    else
    format.html { render action: "new" }
    format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
  end


def update
  @product_type = ProductType.find(params[:id])

  respond_to do |format|
    if @product_type.update_attributes(product_type_params)
      format.html { redirect_to @product_type, notice: 'Product type was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
 end


def destroy
  @product_type = ProductType.find(params[:id])
  @product_type.destroy

  respond_to do |format|
    format.html { redirect_to product_types_url }
    format.json { head :no_content }
  end
 end

 def product_type_params
   params.require(:product_type).permit(
        :name, fields_attributes: [ :field_type, :name, :required ] )
 end
end
class ProductsController < ApplicationController
      def index
        @products = Product.all
      end

      def show
        @product = Product.find(params[:id])
      end

      def new
        @product = Product.new(product_type_id: params[:product_type_id])
      end

      def edit
        @product = Product.find(params[:id])
      end

      def create
        @product = Product.new(product_params)
        if @product.save
          redirect_to @product, notice: 'Product was successfully created.'
        else
          render action: "new"
        end
      end

      def update
        @product = Product.find(params[:id])
        if @product.update_attributes(product_params)
          redirect_to @product, notice: 'Product was successfully updated.'
        else
          render action: "edit"
        end
      end

      def destroy
        @product = Product.find(params[:id])
        @product.destroy
        redirect_to products_url
      end

      private

      def product_params
        params.require(:product).permit(:name, :price, :product_type_id,
                                    :properties)
      end
    end
<%= form_for @product do |f| %>
      <% if @product.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>
          <ul>
          <% @product.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <%= f.hidden_field :product_type_id %>

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name %>
      </div>
      <div class="field">
        <%= f.label :price %><br />
        <%= f.text_field :price %>
      </div>

      <%= f.fields_for :properties, OpenStruct.new(@product.properties) do |builder| %>
        <% @product.product_type.fields.each do |field| %>
          <%= render "products/fields/#{field.field_type}", field: field, f: builder %>
        <% end %>
      <% end %>

      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>
class ProductTypesController
产品控制器.rb

class Product < ActiveRecord::Base
  belongs_to :product_type
  serialize :properties, Hash

 validate :validate_properties

 def validate_properties
   product_type.fields.each do |field|
    if field.required? && properties[field.name].blank?
     errors.add field.name, "must not be blank"
    end
  end
 end
end
class ProductTypesController < ApplicationController

 def index
  @product_types = ProductType.all

   respond_to do |format|
     format.html 
     format.json { render json: @product_types }
   end
 end


 def show
   @product_type = ProductType.find(params[:id])

   respond_to do |format|
     format.html 
     format.json { render json: @product_type }
   end
 end


 def new
   @product_type = ProductType.new

   respond_to do |format|
    format.html 
    format.json { render json: @product_type }
   end
  end

 def edit
  @product_type = ProductType.find(params[:id])
 end


 def create
  @product_type = ProductType.new(product_type_params)

  respond_to do |format|
    if @product_type.save
      format.html { redirect_to @product_type, notice: 'Product type was    successfully created.' }
    format.json { render json: @product_type, status: :created, location: @product_type }
    else
    format.html { render action: "new" }
    format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
  end


def update
  @product_type = ProductType.find(params[:id])

  respond_to do |format|
    if @product_type.update_attributes(product_type_params)
      format.html { redirect_to @product_type, notice: 'Product type was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
 end


def destroy
  @product_type = ProductType.find(params[:id])
  @product_type.destroy

  respond_to do |format|
    format.html { redirect_to product_types_url }
    format.json { head :no_content }
  end
 end

 def product_type_params
   params.require(:product_type).permit(
        :name, fields_attributes: [ :field_type, :name, :required ] )
 end
end
class ProductsController < ApplicationController
      def index
        @products = Product.all
      end

      def show
        @product = Product.find(params[:id])
      end

      def new
        @product = Product.new(product_type_id: params[:product_type_id])
      end

      def edit
        @product = Product.find(params[:id])
      end

      def create
        @product = Product.new(product_params)
        if @product.save
          redirect_to @product, notice: 'Product was successfully created.'
        else
          render action: "new"
        end
      end

      def update
        @product = Product.find(params[:id])
        if @product.update_attributes(product_params)
          redirect_to @product, notice: 'Product was successfully updated.'
        else
          render action: "edit"
        end
      end

      def destroy
        @product = Product.find(params[:id])
        @product.destroy
        redirect_to products_url
      end

      private

      def product_params
        params.require(:product).permit(:name, :price, :product_type_id,
                                    :properties)
      end
    end
<%= form_for @product do |f| %>
      <% if @product.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>
          <ul>
          <% @product.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <%= f.hidden_field :product_type_id %>

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name %>
      </div>
      <div class="field">
        <%= f.label :price %><br />
        <%= f.text_field :price %>
      </div>

      <%= f.fields_for :properties, OpenStruct.new(@product.properties) do |builder| %>
        <% @product.product_type.fields.each do |field| %>
          <%= render "products/fields/#{field.field_type}", field: field, f: builder %>
        <% end %>
      <% end %>

      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>
class ProductsController
\u form.html.erb

class Product < ActiveRecord::Base
  belongs_to :product_type
  serialize :properties, Hash

 validate :validate_properties

 def validate_properties
   product_type.fields.each do |field|
    if field.required? && properties[field.name].blank?
     errors.add field.name, "must not be blank"
    end
  end
 end
end
class ProductTypesController < ApplicationController

 def index
  @product_types = ProductType.all

   respond_to do |format|
     format.html 
     format.json { render json: @product_types }
   end
 end


 def show
   @product_type = ProductType.find(params[:id])

   respond_to do |format|
     format.html 
     format.json { render json: @product_type }
   end
 end


 def new
   @product_type = ProductType.new

   respond_to do |format|
    format.html 
    format.json { render json: @product_type }
   end
  end

 def edit
  @product_type = ProductType.find(params[:id])
 end


 def create
  @product_type = ProductType.new(product_type_params)

  respond_to do |format|
    if @product_type.save
      format.html { redirect_to @product_type, notice: 'Product type was    successfully created.' }
    format.json { render json: @product_type, status: :created, location: @product_type }
    else
    format.html { render action: "new" }
    format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
  end


def update
  @product_type = ProductType.find(params[:id])

  respond_to do |format|
    if @product_type.update_attributes(product_type_params)
      format.html { redirect_to @product_type, notice: 'Product type was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @product_type.errors, status: :unprocessable_entity }
    end
   end
 end


def destroy
  @product_type = ProductType.find(params[:id])
  @product_type.destroy

  respond_to do |format|
    format.html { redirect_to product_types_url }
    format.json { head :no_content }
  end
 end

 def product_type_params
   params.require(:product_type).permit(
        :name, fields_attributes: [ :field_type, :name, :required ] )
 end
end
class ProductsController < ApplicationController
      def index
        @products = Product.all
      end

      def show
        @product = Product.find(params[:id])
      end

      def new
        @product = Product.new(product_type_id: params[:product_type_id])
      end

      def edit
        @product = Product.find(params[:id])
      end

      def create
        @product = Product.new(product_params)
        if @product.save
          redirect_to @product, notice: 'Product was successfully created.'
        else
          render action: "new"
        end
      end

      def update
        @product = Product.find(params[:id])
        if @product.update_attributes(product_params)
          redirect_to @product, notice: 'Product was successfully updated.'
        else
          render action: "edit"
        end
      end

      def destroy
        @product = Product.find(params[:id])
        @product.destroy
        redirect_to products_url
      end

      private

      def product_params
        params.require(:product).permit(:name, :price, :product_type_id,
                                    :properties)
      end
    end
<%= form_for @product do |f| %>
      <% if @product.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>
          <ul>
          <% @product.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

      <%= f.hidden_field :product_type_id %>

      <div class="field">
        <%= f.label :name %><br />
        <%= f.text_field :name %>
      </div>
      <div class="field">
        <%= f.label :price %><br />
        <%= f.text_field :price %>
      </div>

      <%= f.fields_for :properties, OpenStruct.new(@product.properties) do |builder| %>
        <% @product.product_type.fields.each do |field| %>
          <%= render "products/fields/#{field.field_type}", field: field, f: builder %>
        <% end %>
      <% end %>

      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>

禁止保存此产品:


日志

Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.0ms)

    ActionView::Template::Error (undefined method `fields' for nil:NilClass):
        22:   </div>
        23:
        24:   <%= f.fields_for :properties, OpenStruct.new(@product.properties) do |builder| %>
        25:     <% @product.product_type.fields.each do |field| %>
        26:       <%= render "products/fields/#{field.field_type}", field: field, f: builder %>
        27:     <% end %>
        28:   <% end %>
      app/views/products/_form.html.erb:25:in `block (2 levels) in _app_views_products__form_html_erb__38604707748806799_70122829936940'
      app/views/products/_form.html.erb:24:in `block in _app_views_products__form_html_erb__38604707748806799_70122829936940'
      app/views/products/_form.html.erb:1:in `_app_views_products__form_html_erb__38604707748806799_70122829936940'
      app/views/products/new.html.erb:3:in `_app_views_products_new_html_erb__487839569246893265_70122829438980'
在9毫秒内完成500个内部服务器错误(ActiveRecord:0.0毫秒)
ActionView::Template::Error(nil:NilClass的未定义方法“字段”):
22:   
23:
24:   
25:     
26:       
27:     
28:   
app/views/products/_form.html.erb:25:in`block(2层)in_app_view_products_form_html_erb_38604707748806799_70122829936940'
app/views/products/_form.html.erb:24:in'block in_app_view_products_form_html_erb_3860470; 7748806799_70122829936940'
app/views/products/\u form.html.erb:1:in``应用程序视图产品表单html\u erb\u38604707748806799\u 70122829936940'
app/views/products/new.html.erb:3:在“app\u views\u products\u new\u html\u erb\u 487839569246893265\u 70122829438980”中

railscast上有人发表了一条评论,有人回答说这与省略了
有关,我是否遗漏了什么?感谢您花时间查看这个很可能是愚蠢的错误。

问题在于您如何在
ProductsController\new
中的这一行实例化您的
@product

def new
  @product = Product.new(product_type_id: params[:product_type_id])
end
您是通过其id引用产品类型,而不是作为具体引用。由于@product未保存在您的
操作
@product中。product\u type
从未从数据库加载,并且始终为
nil
。要修复,请加载
产品类型
,并直接从新产品中引用它:

def new
  product_type = ProductType.find(params[:product_type_id])
  @product = Product.new(product_type: product_type)
end