rails 4实例变量id在new之后和create之前更改为hash

时间:2014-08-29 17:54:51

标签: ruby-on-rails-4

我正在尝试根据以下答案创建来自已知的父product_type的产品: How to create a nested child from parent object in ruby on rails 4

产品控制器:

...

def new
  @product_type = ProductType.find params[:product_type_id]
  @product = @product_type.products.new
end

def create
  @product_type = ProductType.find params[:product_type_id]
  @product = @product_type.products.build(product_params)
  if @product.save
    flash[:notice] = 'Product created.'
    redirect_to(:action => 'index')
  else
    render("new")
  end
end

新方法的行为符合预期。创建运行时,它会获取:product_type_id而不是整数的哈希值,如控制台中所示:

  

参数:{“utf8”=>“✓”,“authenticity_token”=>“dmGMF6uENfUtkwgwI6GrnvBawIFA6M6Z / ELikQn9gGs =”,“product”=> {“year”=>“2015”,“brand_id”= >“9”,“name”=>“a”,“description”=>“b”,“thumbnail_desc”=>“”,“category_ids”=> [“”,“29”], “product_class_ids”=> [“”],“image_base”=>“”,“media_embed”=>“”,“vendor_sku”=>“”,“msrp”=>“22”,“price_override “=>”“,”visible“=>”1“,”available“=>”1“},”product_type_id“=> {”39“=>”“},”commit“=> ; “保存”}

所以,发现失败了。因此,抛出的错误是未知密钥:39。

模型:ProductTypes有许多产品和产品属于ProductTypes。

这是Rails2的一个早该重写的重写。在那里,@ product_type实例变量从new保存到create。

感谢您的考虑和帮助。

以下是产品形式:

<%= form_for([:admin, @product]) do |form| %>
  <% if @product.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@product.errors.count, "error") %> prohibited this page from being saved:</h2>

      <ul>
      <% @product.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

<table cellpadding="0" cellspacing="0" class="admintable">
   <tr> 
    <th>Year</th>
    <td><%= form.text_field :year, :size => 5 %></td>
  </tr>
  <tr>
    <th>Brand</th>
    <td><%= form.select(:brand_id, @brands.map {|b| [b.name, b.id]}) %></td>
  </tr>
  <tr>
    <th>Product Name</th>
    <td><%= form.text_field :name, :size => 30 %></td>
  </tr>
  <tr> 
    <th>Description</th>
    <td><%= form.text_area :description, :cols => 60, :rows => 30 %></td>
  </tr>
  <tr> 
    <th>Thumbnail Description</th>
    <td><%= form.text_area :thumbnail_desc, :cols => 60, :rows => 5 %></td>
  </tr>
  <tr> 
    <th>Categories</th>
    <td>
    <%= form.collection_select :category_ids, Category.sorted, :id, :name, {}, {:multiple => true, include_blank: true, :size => 20 } %>
    </td>
  </tr>

  <tr> 
    <th>Product Class</th>
    <td>
    <%= form.collection_select :product_class_ids, ProductClass.options_for_select(@product.product_type_id), :id, :name, {}, {:multiple => true, include_blank: true, :size => 4 } %>
    </td>
  </tr>

  <tr> 
    <th>Image Base</th>
    <td><%= form.text_field :image_base, :size => 40 %></td>
  </tr>

  <tr> 
    <th>Media Embed Code</th>
    <td><%= form.text_area :media_embed, :cols => 60, :rows => 5 %></td>
  </tr>

  <tr> 
    <th>Vendor SKU</th>
    <td><%= form.text_field :vendor_sku, :size => 30 %></td>
  </tr>

  <% if @product_type.has_price? -%>
  <tr> 
    <th>MSRP</th>
    <td><%= form.text_field :msrp, :size => 5 %></td>
  </tr>

  <tr> 
    <th>BW Price</th>
    <td><%= form.text_field :price_override, :size => 5 %></td>
  </tr>
  <% end -%>

  <tr>
    <th>Visible?</th>
    <td><%= form.check_box :visible %></td>
  </tr>

  <tr>
    <th>Available?</th>
    <td><%= form.check_box :available %></td>
  </tr>

  <% unless @product.active -%>
  <tr>
    <th>Active</th>
    <td><%= form.check_box :active %></td>
  </tr>
  <% end -%>

  <%= hidden_field :product_type_id, "#{@product_type.id}" %> 
  <tr> 
    <th>&nbsp;</th>
    <td><%= form.submit "Save" %></td>
  </tr>
</table>
<% end %>

产品型号:

class Product < ActiveRecord::Base

  belongs_to :brand
  belongs_to :product_type

  has_and_belongs_to_many :categories
  has_and_belongs_to_many :colors
  has_and_belongs_to_many :product_classes

  validates_presence_of :name, :categories
  validates_presence_of :msrp, :if => Proc.new { |p| p.price_override != nil }
  validates_numericality_of :year, :greater_than => 2007, :allow_nil => true
  validates_numericality_of :msrp, :price_override, :greater_than => 0, :allow_nil => true

  scope :sorted, lambda { order("name ASC") }
  scope :notdeleted, lambda { where(:deleted_at => nil) }

  def display_name(model = nil)
    str = model ? model.actual_name : name
    str = "#{brand_year_prefix} #{str}" if product_type.name_has_prefix?
    str
  end

  def brand_year_prefix
    str = brand.display_name if product_type.name_includes_brand
    str = "#{year} #{str}" if product_type.name_includes_year
    str.strip
  end

  def model_name(model, include_brand = false)
    str = model.actual_name
    str = "#{brand.display_name} #{str}" if include_brand
    str = "#{year} #{str}" if product_type.model_name_includes_year
    str
  end

  def price
    price_override ? price_override : msrp
  end

  def onsale
    price_override  ? '<span class="red">Sale: ': '<span class=""> '
  end

  def has_product_pricing?
    price != nil
  end

  def has_one_price?
    has_product_pricing? && models.all? { |m| !m.has_model_pricing? }
  end

  def can_be_purchased?
    visible? && available? && deleted_at.nil? && (!product_type.has_models || models.any? { |m| m.can_be_purchased? })
  end

  def real_image_path
    image_base.blank? ? AppConfig.default_product_image : image_base
  end

  def thumb_image_path
    real_image_path + "-t.jpg"
  end

  def standard_image_path
    real_image_path + "-s.jpg"
  end

  def large_image_path
    real_image_path + "-l.jpg"
  end

  def active
    deleted_at.nil?
  end

  def active=(val)
    self.deleted_at = [nil, '', '0', false].member?(val) ? Time.now : nil
  end

  def self.compare_year(a, b)
    a_has_year = !a.year.blank? && a.product_type.name_includes_year?
    b_has_year = !b.year.blank? && b.product_type.name_includes_year?
    return 0 if !a_has_year && !b_has_year
    return -1 if a_has_year && !b_has_year
    return 1 if b_has_year && !a_has_year
    b.year <=> a.year
  end

  def self.compare_brand(a, b)
    a_has_brand = !a.brand.nil? && a.product_type.name_includes_brand?
    b_has_brand = !b.brand.nil? && b.product_type.name_includes_brand?
    return 0 if !a_has_brand && !b_has_brand
    return -1 if a_has_brand && !b_has_brand
    return 1 if b_has_brand && !a_has_brand
    a.brand.display_name <=> b.brand.display_name
  end
end

product_type型号:

class ProductType < ActiveRecord::Base

  has_many :product_classes
  has_many :products

  validates_presence_of :name

  scope :sorted, lambda { order("name ASC") }
  scope :notdeleted, lambda { where(:deleted_at => nil) }

  def active
     deleted_at.nil?
  end

  def active=(val)
     self.deleted_at = [nil, '', '0', false].member?(val) ? Time.now : nil
  end

end

1 个答案:

答案 0 :(得分:0)

要解决这个问题,我必须重构代码。重构的新方法:

<%= form_for([:admin, @product], :url => {:action => 'create', :product_type_id => @product_type.id}) do |form| %>

<%= render :partial => 'form', :locals => {:form => form} %>

<div class="form-buttons">
  <%= submit_tag("Create #{@product_type.name}") %>
</div>

<% end %>

然后_form.html.erb只有html表单元素。