新手问题 一个 simple_form 下对两个 model 操作,并且一个更新,一个创建,请问如何设置?

QueXuQ · June 07, 2013 · Last by xhj6 replied at June 08, 2013 · 3321 hits

我有两个 model

class Order < ActiveRecord::Base
  has_many :lists
  attr_accessible :name
end

class List < ActiveRecord::Base
  belongs_to :order
  attr_accessible :number, :name, :about
end

现在我在一个 form 里,创建 order,如下:

= simple_form_for(@order) do |f|
  = f.input :name
  = f.simple_fields_for :list_attributes do |d|
    = d.input :number
    = d.input :name
    = d.input :about
  = f.button :submit

正常情况下来说,如果我 new 一个 order 的时候,同事新建一个 list,是可以使用上面的 form 的。 但是我现在的情况是这样,@order = Order.new,order 是创建的。但是 list 不一定是创建的,可以说是更具 number 来判定,如果 number 在数据库中存在,只需要 update list 的 name 和 about 字段,并且order_id = @order.id. 但是,如果 number 是在数据库内不存在的话,自然就 new 一个 List。请问这样应该在 controller 或者 model 里怎么写比较好呢?

你的问题属于 google 和看文档就能够解决的问题,就是一个标准的 Nested Model Form 的应用场景,与 simple_form 毛关系都没有。

很简单,就是需要在 Order 中加入:

accepts_nested_attributes_for :lists

然后把 List 的 number 字段改为 id 即可。

ActiveRecord::NestedAttributes 会自动判断给定的 id 是否存在,存在则更新,正好满足你的需求。你如果坚持要用 number 作为字段名的话,理由是什么?

详情参见:

#196 Nested Model Form (revised) ActiveRecord::NestedAttributes::ClassMethods

我觉得这样就可以了(。・ω・。)

class Order
  def ❨╯°□°❩╯︵(┻━┻)
    create_or_use_list ┻━┻
  end
  def self.(\—_—)\(params)
    self.new(params)
  end

  private

  def create_or_use_list(list_params)
    # logic goes here
  end
end


class OrdersController < ApplicationController

  def create
    @order = Order.(\—_—)\ ┯━┯

    if @order.❨╯°□°❩╯︵ ┻━┻
      flash[:notice] = t('common.update_success')
    end
    respond_with @order
  end

  def ┯━┯
    params.require(:order).permit(:name, order: [:name, :number, :about])
  end

  def ┻━┻
    ┯━┯.delete :order
  end
end

方法名不要卖萌啊啊啊啊啊❨╯°□°❩╯︵ ┻━┻

如何更好地回答 http://ruby-china.org/topics/10251

看得出楼主已经做过功课,顶楼也给了代码,不要这样回答。

#1 楼 @xhj6 不可以通过 id 判断啊。例如:如果你是用户填写的,你只知道 list 的 number,你不可能会知道 id 是多少的。 或者这样说,如果你是商家,你在填写东西的时候,你只知道这个商品的 number,id 是数据库里的东西,商家不知道的嘛。

#2 楼 @aptx4869 这个我试试怎么样。不过那变量有点混乱😄

@Rei 感谢提醒,虚心接受。

#5 楼 @QueXuQ 如果的确只能用 number 的话,可以将 id 作为隐含字段,客户填写 number 后以 ajax 的方式取出 id 值 或 删除 id 字段就是,(删除线不起作用了?)可以在 Controller 中把 id 查询出来更新一下 :list_attributes 就是。

当然,如果多个 Nested Form 中都出现了 number 取代 id 的情景的话,你也可以考虑给 assign_nested_attributes_for_collection_association 这个方法打猴子补丁,这个方法位于rails/activerecord/lib/active_record/nested_attributes.rb

@aptx4869 不太赞成你的方法哈,你的代码实际上以 create_or_use_list(list_params) 为核心,其它的都是在打酱油之余负责买萌的,呵呵。

不过即使方法名不买萌,这样的代码也增加了不必要的复杂性,代码行数增加数倍、方法名增加数个不说,还失去了 accepts_nested_attributes_for 提供的一系列便利,这些便利其中最常用的就是使用 reject_if 进行过滤,你懂的,比如像下面这样:

accepts_nested_attributes_for :lists, 
  :reject_if => proc { |attributes| attributes['about'].eql? "宇宙真理" }

#6 楼 @xhj6 其实只增加了一个 create_or_use_list 方法……controller 里面的其实不算增加的,rails4 里面用 strong_parameters 必须一个个自己手动写 permit……所以我才想要 ❨╯°□°❩╯︵ ┻━┻ 其实自己重定义lists_attributes=方法也是可以的,好像更简单一些

@aptx4869 的确处理 list_attributes 更简单些,借鉴你的思路,我把我 6 楼的答案改了下。

accepts_nested_attributes_for :lists 还是必需的,一行代码就可解决问题的,何必去追求其它奇淫巧技呢,对不对?

另外,为什么删除线不起作用了呢? @huacnlee

You need to Sign in before reply, if you don't have an account, please Sign up first.