【问题标题】:Using fields_for in Rails 4...does not save the new fields在 Rails 4 中使用 fields_for ......不会保存新字段
【发布时间】:2016-06-06 21:18:26
【问题描述】:

我正在尝试在我正在处理的项目中使用 fields_for 辅助方法。原始表格可以正常工作并保存得很好。新属性不保存,我得到一个 NoMethodError 和一个未定义的方法。我错过了什么?!

这是我的列表模型:

class Listing < ActiveRecord::Base
has_one :listing_commerical_attribute
accepts_nested_attributes_for :listing_commerical_attribute, :allow_destroy => true

这是我的 listing_commercial_attribute 模型:

class ListingCommercialAttribute < ActiveRecord::Base
  belongs_to :listing
  accepts_nested_attributes_for :listing
end

这是我的控制器:

def new
  @listing.build_listing_commercial_attribute

  respond_to do |format|
    format.html # new.html.erb
    format.json { render json: @listing }
  end
end

private

def commercial_params
  params.require(:commerical_listing_attribute)
      .permit(:gas_pipe_size,
              :amperage,
              :basement_ceiling_height,
              :ceiling_height,
              :door_size,
              :zoning,
              :previous_use,
              :community_board,
              :delivery_date,
              :key_money,
              :security_deposit,
              :price_per_sq_ft,
              :did_size)
end

这是我的 _form.html.erb:

<h2 class="text-center">Commercial</h2>
 <%= f.fields_for :listing_commerical_attributes do |ff| %>
<div class="field">
  <%= ff.label :gas_pipe_size, "Gas Pipe Size", class: "general-text-label" %>
  <%= ff.number_field :gas_pipe_size, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :amperage, "Amperage", class: "general-text-label" %>
  <%= ff.number_field :amperage, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :ceiling_height, "Ceiling Height", class: "general-text-label" %>
  <%= ff.number_field :ceiling_height, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :basement_ceiling_height, "Basement Ceiling Height", class: "general-text-label" %>
  <%= ff.number_field :basement_ceiling_height, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :door_size, "Door Size", class: "general-text-label" %>
  <%= ff.number_field :door_size, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :zoning, "Zoning", class: "general-text-label" %>
  <%= ff.text_field :zoning, class: "general-text-field" %>
</div>
<div class="field">
  <label for="tenant_improvements" class="general-text-label">Tenant Improvements <small>(If Applicable)</small></label>
  <%= ff.text_area :tenant_improvements, :rows => "4", class: "general-text-area" %>
</div>
<div class="field">
  <label for="previous_use" class="general-text-label">Previous Use <small>(If Applicable)</small></label>
  <%= ff.text_area :previous_use, :rows => "4", class: "general-text-area" %>
</div>
<div class= "field">
  <%= ff.label :community_board, "Community Board", class: "general-text-label" %>
  <%= ff.text_field :community_board, class: "general-text-field" %>
</div>
<div class="field">
  <%= ff.label :delivery_date, "Delivery Date", class: "general-text-label" %>
  <div class="input-group">
    <span class="input-group-addon"><i class="nklyn-icon-calendar"></i></span>
    <%= ff.text_field :delivery_date, :class => "datepicker general-text-field" %>
</div>
<div class="field">
  <%= ff.label :key_money, "Key Money", class: "general-text-label" %>
  <div class="input-group">
    <span class="input-group-addon"><i class="nklyn-icon-money-bills"></i></span>
    <%= f.text_field :key_money, class: "general-text-field", value: number_with_precision(f.object.price, delimiter: ',', precision: 0) %>
  </div>
</div>
<div class="field">
  <%= ff.label :security_deposit, "Security Deposit", class: "general-text-label" %>
  <div class="input-group">
    <span class="input-group-addon"><i class="nklyn-icon-money-bills"></i></span>
    <%= f.text_field :security_deposit, class: "general-text-field", value: number_with_precision(f.object.price, delimiter: ',', precision: 0) %>
  </div>
</div>
<div class="field">
  <%= ff.label :price_per_sq_ft, "Price Per Sq Ft", class: "general-text-label" %>
  <div class="input-group">
    <span class="input-group-addon"><i class="nklyn-icon-money-bills"></i></span>
    <%= f.text_field :price_per_sq_ft, class: "general-text-field", value: number_with_precision(f.object.price, delimiter: ',', precision: 0) %>
  </div>
</div>
<div class="field">
  <%= ff.label :did_size, "Drive In Doors Size", class: "general-text-label" %>
  <%= ff.number_field :did_size, class: "general-text-field" %>
</div>
<% end %>

更新

  1. 我对 ListingCommercialAttribute 模型进行了更改并删除了接受嵌套属性。

  2. 我将 f.fields_for 更改为单数而不是复数。

  3. 我在父级之后添加了嵌套属性(见下文)

    def listing_params
       params.require(:listing)
          .permit(:access,
              :address,
              :apartment,
              :cats_ok,
              :cross_streets,
              :dogs_ok,
              :latitude,
              :longitude,
              :amenities,
              :date_available,
              :bathrooms,
              :bedrooms,
              :description,
              :fee,
              :exclusive,
              :featured,
              :rental,
              :residential,
              :landlord_contact,
              :listing_agent_id,
              :sales_agent_id,
              :neighborhood_id,
              :pets,
              :photo,
              :photo_tag,
              :primaryphoto,
              :price,
              :square_feet,
              :station,
              :status,
              :subway_line,
              :term,
              :title,
              :utilities,
              :move_in_cost,
              :owner_pays,
              :private,
              :office_id,
              :full_address,
              :zip,
              :convertible,
              :landlord_llc,
              :pinned,
              :image,
              listing_commercial_attribute_attributes: [
              :gas_pipe_size,
              :amperage,
              :basement_ceiling_height,
              :ceiling_height,
              :door_size,
              :zoning,
              :previous_use,
              :community_board,
              :delivery_date,
              :key_money,
              :security_deposit,
              :price_per_sq_ft,
              :did_size])
    end
    
  4. 这是我的新控制器操作:

    def edit
       @listing.attributes = listing_params
    end
    
    def create
       @listing.attributes = listing_params
    
       respond_to do |format|
         if @listing.save
            format.html { redirect_to @listing, notice: 'Listing was successfully created.' }
            format.json { render json: @listing, status: :created, location: @listing }
         else
            format.html { render action: "new", notice: "Correct the mistakes below to create the new listing" }
            format.json { render json: @listing.errors, status: :unprocessable_entity }
        end
      end
    end
    

但现在我在 Listings#show 错误中收到 NoMethodError。我为商业属性创建了一个部分。既然它们在强大的参数中,难道不应该将它们包括在内吗?还是我完全误解了这一点?!

这是部分内容:

    Gas Pipe Size: <%= listing_commercial_attributes.gas_pipe_size(@listing) %>
    Amperage: <%= listing_commercial_attribute.amperage(@listing) %>
    Basement Ceiling Height: <%= listing_commercial_attribute.basement_celing_height(@listing) %>
    Ceiling Height: <%= listing_commercial_attribute.ceiling_height(@listing) %>
    Door Size: <%= listing_commercial_attribute.door_size(@listing) %>
    Zoning: <%= listing_commercial_attribute.zoning(@listing) %>
    Build to Suit: <%= listing_commercial_attribute.build_to_suit(@listing) %>
    Previous Use: <%= listing_commercial_attribute.previous_use(@listing) %>
    Community Board: <%= listing_commercial_attribute.community_board(@listing) %>
    Delivery Date: <%= listing_commercial_attribute.delivery_date(@listing) %>
    Key Money: <%= listing_commercial_attribute.key_money(@listing) %>

更新 #2

我把它改成了单数。

这是完整的错误。

Listings中的NameError#show

显示 /Users/Code/app/views/listings/_commercial_attributes.html.erb 其中第 1 行提出:

# 的未定义局部变量或方法 `listing_commercial_attribute' 你的意思是? Listing_collection_url

  • 燃气管道尺寸:
  • 安培数:
  • 地下室天花板高度:
  • 天花板高度:
  • 门尺寸:
  • 分区:

模板包含的痕迹:app/views/listings/_listing_content_area.html.erb、app/views/listings/show.html.erb


更新 #3

  def show
      @my_listing_collections = ListingCollection.with_agent(current_agent).order("created_at DESC")
      @listing_commercial_attributes = ListingCommercialAttribute.find(params[:id])
      @regions = Region.order(name: :asc)
      @listing = Listing.includes(:photos, :likes, :interested_agents).find(params[:id])

      if @listing.private && cannot?(:create, Listing)
        redirect_to listings_path, notice: 'This listing is no longer available'
      else
        agent = Agent.where(id: params[:agent_id]).first
        @page = Listings::ShowView.new(@listing, agent)

        respond_to do |format|
          format.html
        end
      end
    end

我不断收到此错误:

ListingsController#show 中的 ActiveRecord::RecordNotFound

找不到 'id'=5755 的 ListingCommercialAttribute

它正在搜索 id 为 5755 的商业属性,但那是列表 id。我不知道该传递什么...

【问题讨论】:

  • 哪些新属性没有被保存?
  • 上面列出的部分。它们没有被保存到数据库中,我遇到了那个错误。

标签: ruby-on-rails ruby-on-rails-4 fields-for


【解决方案1】:
  1. 不要在两个模型上定义accepts_nested_attributes_for。仅在父模型上。否则你会遇到循环依赖问题。在这种情况下,父模型看起来像是一个列表,因此请从 ListingCommercialAttribute 中删除 accepts_nested_attributes_for :listing
  2. f.fields_for 的第一个参数应该是关联的名称,而您的名称稍有偏差。你有has_one : listing_commerical_attribute,所以你想要f.fields_for : listing_commerical_attribute
  3. Strong 参数应该首先需要您的父对象,然后再包括嵌套对象。此外,您必须将 _attributes 附加到嵌套属性名称的末尾。

所以,对于 3:

def listing_params
  params.require(:listing)
        .permit(:id,
                # ...
                listing_commercial_attribute_attributes: [ # Note: _attributes
                  :gas_pipe_size,
                  # ...
                ])
end
  1. 在创建/编辑操作中,请务必从强参数方法中设置参数:@listing.attributes = listing_params

accepts_nested_attributes_forStrong Parameters 的文档中了解更多信息。

【讨论】:

  • 我进行了建议的更改,但仍然遇到一些错误。你介意再看看吗。我输入了上面的更新!先感谢您! @pdobb
  • 你没有显示足够多的错误让我知道究竟是什么问题。但是,在“显示”页面中,您不应该使用复数形式。
  • 看起来你还没有将局部变量 `listing_commercial_attribute' 传递给你的局部变量。
  • 我解决了这些错误,但商业属性仍然没有保存到数据库中。我忘记了什么? @pdobb
  • 在这种情况下,首先要尝试的是在控制器中的 attributes = 调用之后插入调试器/绑定,并将 listing_params 中的内容与您期望的内容进行比较,然后比较设置的内容您在listing_params 中看到的对象。例如。检查您的 @listing 对象和关联的 @listing.listing_commercial_attribute 对象。他们应该在这一点上设定他们的价值观。如果不是,那么您可以排除保存问题并查看强参数。如果是这样,那么您可以使用实际的 save 命令更多地查看验证错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2015-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多