Ruby on Rails 从一种形式保存在两个表中

Posted

技术标签:

【中文标题】Ruby on Rails 从一种形式保存在两个表中【英文标题】:Ruby on Rails Saving in two tables from one form 【发布时间】:2014-07-14 22:14:24 【问题描述】:

我有两个模型 Hotel 和 Address。 关系是:

class Hotel
  belongs_to :user
  has_one    :address
  accepts_nested_attributes_for :address

class Address
  belongs_to :hotel

我需要从一个表格保存在 hotels 表和 addresses 表中。

输入形式很简单:

<%= form_for(@hotel) do |f| %>

  <%= f.text_field :title %>
  ......other hotel fields......

  <%= f.fields_for :address do |o| %>
    <%= o.text_field :country %>
    ......other address fields......

  <% end %>
<% end %>

酒店管理员:

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)
    address = @hotel.address.build
    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

但是这段代码不起作用。

添加 1 个 酒店参数:

  private
    def hotel_params
      params.require(:hotel).permit(:title, :stars, :room, :price)
    end

添加 2 个

主要问题是我不知道如何正确呈现表单。此 ^^^ 表单甚至不包括地址字段(国家、城市等)。但是如果在行

<%= f.fields_for :address do |o| %> 

我将 :address 更改为 :hotel,我在表单中获得了地址字段,但在这种情况下,:address 表中当然没有保存任何内容。我不明白从 1 个表格中保存 2 个表的原理,非常抱歉,我是 Rails 新手...

【问题讨论】:

能否也提供您的hotel_params 方法。 您能否提供更多关于提交此表单的输出的信息? @Vapire 当然添加了hotel_params。 @khaled_gomaa,当然,我在 ADD2 中描述了这个表格。 你目前拥有form 的方式是正确的。不要搞砸了。我猜这里的罪魁祸首是你的newcreate 方法。你能试试我的回答吗?说它是否有效。 【参考方案1】:

您使用 wrong method 将您的孩子附加到父母。而且它也是 has_one relation,所以您应该使用 build_model 不是 model.build。你的 newcreate 方法应该是这样的

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
    @hotel.build_address #here
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)

    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

更新

您的hotel_params 方法应如下所示

def hotel_params
   params.require(:hotel).permit(:title, :stars, :room, :price,address_attributes: [:country,:state,:city,:street])
end

【讨论】:

感谢您的关注!使用“def new”中的地址 = @hotel.address.build 行,我在此行收到错误:未定义方法 `build' for nil:NilClass when try to access add page.. nil:NilClass 的仍​​然未定义方法 `build'。 @AlMacks 我已经更新了我的答案。现在应该可以了。 外键呢?我将如何设置地址:hotel_id = 酒店:id?【参考方案2】:

你不应该再次建立地址

class HotelsController < ApplicationController
  def new
    @hotel = Hotel.new
  end

  def create
    @hotel = current_user.hotels.build(hotel_params)
    # address = @hotel.address.build 
    # the previous line should not be used
    if @hotel.save      
      flash[:success] = "Hotel created!"
      redirect_to @hotel
    else
      render 'new'      
    end    
  end

【讨论】:

谢谢,khaled_gomaa!【参考方案3】:

这里的底线是你需要正确使用f.fields_for方法。

--

控制器

您需要做几件事才能使该方法发挥作用。首先,您需要构建关联的对象,然后您需要能够以正确的方式将数据传递给您的模型:

#app/models/hotel.rb
Class Hotel < ActiveRecord::Base
   has_one :address
   accepts_nested_attributes_for :address
end

#app/controllers/hotels_controller.rb
Class HotelsController < ApplicationController
    def new
       @hotel = Hotel.new
       @hotel.build_address #-> build_singular for singular assoc. plural.build for plural
    end

    def create
        @hotel = Hotel.new(hotel_params)
        @hotel.save
    end

    private

    def hotel_params
        params.require(:hotel).permit(:title, :stars, :room, :price, address_attributes: [:each, :address, :attribute])
    end
end

这应该适合你。

--

表格

表单的一些提示 - 如果您正在加载表单并且没有看到 f.fields_for 块显示,这基本上意味着您没有正确设置您的 ActiveRecord Model(在 new 操作中)

我上面写的(与Pavan 写的非常相似)应该可以为你工作

【讨论】:

@Richard 我看不到 f.fields_for 你能帮我解决这个问题吗? 你在用&lt;%= f.fields_for ...吗? 外键怎么办?

以上是关于Ruby on Rails 从一种形式保存在两个表中的主要内容,如果未能解决你的问题,请参考以下文章

单击时禁用引导表行并将其保存在 Ruby on Rails 中

在 ruby​​ on rails 中使用连接表

Ruby on Rails 中的表关联

Ruby on Rails Scaffolding:同一张表的两个外键

Ruby on Rails - 从 CSV 文件导入数据

Ruby On Rails:用于其他语言的复数形式