RoR如何访问通过相同表单发布的多个模型参数

时间:2017-05-22 20:48:59

标签: ruby-on-rails ruby forms ruby-on-rails-5

我正在使用Ruby on Rails构建一个简单的表单来提交订单。

我的表单需要提交来自3种不同模型的信息:用户,catalog_item和订单本身。

这是我的订单模式:

class Order < ApplicationRecord
    after_initialize :default_values
    validates :quantity, presence: true

    belongs_to :user
    belongs_to :catalog_item
    validates :user_id, presence: true
    validates :catalog_item_id, presence: true

    accepts_nested_attributes_for :user
    validates_associated :user
end

这是我的用户模型:

class User < ApplicationRecord
    has_many :orders
end

这是我的控制人员:

class OrdersController < ApplicationController

def checkout
    @order = Order.new(catalog_item: CatalogItem.find(params[:catalog_item_id]), user: User.new)
end

def create
    @order = Order.new(order_params)
    if @order.save
        # redirect_to confirmation_path
    else
        # redirect_to error_path
    end
end

private
    def user_params
    [:name, :email, :phone_number]
  end

    def order_params
        params.require(:order).permit(:id, :catalog_item_id, user_attributes: user_params)
    end
end

这是我的观点:

<%= form_for @order do |order_form| %>
    <%= order_form.hidden_field :catalog_item_id %>
    <%= order_form.fields_for :user do |user_fields| %>
        <%= user_fields.label :name %>
    <%= user_fields.text_field :name %>
    <%= user_fields.label :email %>
    <%= user_fields.text_field :email %>
    <%= user_fields.label :phone_number %>
    <%= user_fields.text_field :phone_number %>
    <% end %>
    <%= order_form.submit %>
<% end %>

如果表单为HTML:

<form class="new_order" id="new_order" action="/orders" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="+z8JfieTzJrNgsr99C4jwBtXqIrpNtiEGPdVi73qJrpiGPpjYzbLwUng+e+yp8nIS/TLODWVFQtZqS/45SUoJQ==">
    <input type="hidden" value="1" name="order[catalog_item_id]" id="order_catalog_item_id">
    <label for="order_user_attributes_name">Name</label>
    <input type="text" name="order[user_attributes][name]" id="order_user_attributes_name">
    <label for="order_user_attributes_email">Email</label>
    <input type="text" name="order[user_attributes][email]" id="order_user_attributes_email">
    <label for="order_user_attributes_phone_number">Phone number</label>
    <input type="text" name="order[user_attributes][phone_number]" id="order_user_attributes_phone_number">
    <input type="submit" name="commit" value="Create Order" data-disable-with="Create Order">

以下是我的路线:

get 'checkout/:catalog_item_id', to: 'orders#checkout', as: 'checkout'
post 'orders', to: 'orders#create'

当我尝试将@order保存在操作create中时,我收到此错误:

#<ActiveModel::Errors:0x007fe95d58b698 @base=#<Order id: nil, quantity: 1, created_at: nil, updated_at: nil, user_id: nil, catalog_item_id: 1>, @messages={:user_id=>["can't be blank"]}, @details={:user_id=>[{:error=>:blank}]}>

但是,如果我这样做,它确实有效:

@catalog_item = CatalogItem.find(order_params[:catalog_item_id])
@user = User.new(order_params[:user_attributes])
@user.save
@order = Order.new(catalog_item: @catalog_item, user: @user)

这是发布表单时在HTTP请求中发送的内容:

order[catalog_item_id]:1
order[user_attributes][name]:Ana
order[user_attributes][email]:ana@gmail.com
order[user_attributes][phone_number]:123123123
commit:Create Order

我是RoR的新手,我不明白为什么order_params没有用户,但它确实有catalog_item_id。

任何帮助都将得到真正的赞赏。谢谢!

3 个答案:

答案 0 :(得分:0)

假设您的IdContext.Connection.IOHandler.ReadStream(FS, -1, False)模型Order,我的建议 - 轨道最佳实践&#34;解决方案如下:

有关详细信息,请参阅Rails Nested Attributes。基本上嵌套属性的作用是它允许你创建&#34;也只是一个命令中的相关记录(在您的示例中,关联的用户):

belongs_to :user

现在您也可以在创建订单时传递# example code: Order.create( catalog_item_id: 1, user_attributes: { name: 'Foo', email: 'foo@bar.com' } ) # above will create two records (i.e.): # 1) <Order id: 1 catalog_item_id: 1> # 2) <User id: 1, order_id: 1, name: 'Foo', email: 'foo@bar.com'> 作为哈希的一部分,只需将user_attributes视为请求参数的一部分,请参阅{ {1}}下面。

型号:

user_attributes

控制器:

controller

视图;

# app/models/order.rb
belongs_to :user

accepts_nested_attributes_for :user

# from our discussion, the validation needs to be updated into:
validates :user, presence: true
validates :category_item, presence: true

答案 1 :(得分:0)

用户是一个类,因此fields_for :user为新用户对象创建字段。

尝试拨打order_form.fields_for而不是fields_for,将fields_for范围限定为您的订单对象。

答案 2 :(得分:0)

如果您希望用户能够从项目的节目视图创建订单,您可以设置嵌套路线:

resources :catalog_items do 
  resources :orders, only: [:create]
end

确保你有

class Order < ApplicationRecord
  belongs_to :user
  belongs_to :catalog_item_id
  accepts_nested_attributes_for :user
  validates_associated :user # triggers user validations
end

class CatalogItem
  has_many :orders
end

然后你可以这样做:

# /app/views/orders/_form.html.erb
<%= form_for [@catalog_item, @order || @catalog_item.orders.new] do |order_form| %>
  <%= order_form.fields_for :user do |user_fields| %>
    <%= user_fields.label :name %>
    <%= user_fields.text_field :name %>
    <%= user_fields.label :email %>
    <%= user_fields.text_field :email %>
    <%= user_fields.label :phone_number %>
    <%= user_fields.text_field :phone_number %>
  <% end %>
  <%= order_form.submit %>
<% end %>

# /app/views/catalog_items/show 
<%= render partial: 'orders/form' %>

这会将表单网址设置为/catalog_items/:catalog_item_id/orders。这意味着我们通过URL传递catalog_item_id而不是表格参数 -   - 这是一种更好的做法,因为它使路线具有描述性和RESTful。

然后设置控制器:

class OrderController
  # POST /catalog_items/:catalog_item_id/orders
  def create
    @catalog_item = CatalogItem.find(params[:catalog_item_id])
    @order = @catalog_item.orders.new(order_params)
    # Uncomment the next line if you have some sort of authentication like Devise 
    # @order.user = current_user if user_signed_in?
    if @order.save
      redirect_to @catalog_item, success: 'Thank you for your order'
    else
      render 'catalog_items/show' # render show view with errors.
    end
  end

  # ...

  private

  def user_params
    [:name, :email, :phone_number]
  end

  def order_params
    params.require(:order)
          .permit(:id, user_attributes: user_params)
  end
end