Accepts_nested_attributes_for 链接到现有记录,而不是创建新记录

发布于 2024-10-01 18:39:08 字数 1424 浏览 7 评论 0原文

我有以下型号

class Order < AR::Base
  has_many :products

  accepts_nested_attributes_for :products
end

class Product < AR::Base
  belongs_to :order
  has_and_belongs_to_many :stores

  accepts_nested_attributes_for :stores
end

class Store < AR::Base
  has_and_belongs_to_many :products
end

现在我有一个订单视图,我想在其中更新产品的商店。 问题是我只想将产品连接到数据库中的现有商店,而不是创建新商店。

我在订单视图中的表单看起来像这样(使用 Formtastic):

= semantic_form_for @order do |f|
  = f.inputs :for => :live_products do |live_products_form|
    = live_products_form.inputs :for => :stores do |stores_form|
      = stores_form.input :name, :as => :select, :collection => Store.all.map(&:name)

虽然它是嵌套的,但它工作得很好。 问题是,当我选择一个商店并尝试更新订单(及其产品和商店)时,Rails 会尝试使用该名称创建一个新商店。我希望它只使用现有的商店并将产品连接到该商店。

任何帮助表示赞赏!

编辑1:

最后我以一种非常粗略的方式解决了这个问题:

# ProductsController

def update
  [...]

  # Filter out stores
  stores_attributes = params[:product].delete(:stores_attributes)

  @product.attributes = params[:product]

  if stores_attributes.present?
    # Set stores
    @product.stores = stores_attributes.map do |store_attributes|
      # This will raise RecordNotFound exception if a store with that name doesn't exist
      Store.find_by_name!(store_attributes[:name])
    end
  end

  @order.save

  [...]
end

编辑2:

巴勃罗的解决方案更加优雅,应该比我的更受青睐。

I have the following models

class Order < AR::Base
  has_many :products

  accepts_nested_attributes_for :products
end

class Product < AR::Base
  belongs_to :order
  has_and_belongs_to_many :stores

  accepts_nested_attributes_for :stores
end

class Store < AR::Base
  has_and_belongs_to_many :products
end

Now I have a order view where I want to update the shops for the product.
The thing is that I only want to connect the products to the existing shops in my db, not create new ones.

My form in the order view looks like this (using Formtastic):

= semantic_form_for @order do |f|
  = f.inputs :for => :live_products do |live_products_form|
    = live_products_form.inputs :for => :stores do |stores_form|
      = stores_form.input :name, :as => :select, :collection => Store.all.map(&:name)

Although its nested it works fine.
The problem is that, when I select a store and try to update the order (and the products and stores with it), Rails tries to create a new store with that name. I want it to just use the existing store and connect the product to that.

Any help appreciated!

EDIT 1:

In the end I solved this problem in a very crude way:

# ProductsController

def update
  [...]

  # Filter out stores
  stores_attributes = params[:product].delete(:stores_attributes)

  @product.attributes = params[:product]

  if stores_attributes.present?
    # Set stores
    @product.stores = stores_attributes.map do |store_attributes|
      # This will raise RecordNotFound exception if a store with that name doesn't exist
      Store.find_by_name!(store_attributes[:name])
    end
  end

  @order.save

  [...]
end

EDIT 2:

Pablo's solution is much more elegant and should be preferred over mine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

椒妓 2024-10-08 18:39:08

尝试实现一个 :reject_if 来检查 Store 是否已存在,然后使用它:

class Product < AR::Base
  belongs_to :order
  has_and_belongs_to_many :stores

  accepts_nested_attributes_for :stores, :reject_if => :check_store

  protected

    def check_store(store_attr)
      if _store = Store.find(store_attr['id'])
        self.store = _store
        return true
      end
      return false
    end
end

我的这段代码在当前项目中运行良好。

如果您找到更好的解决方案,请告诉我。

Try to implement a :reject_if that check if the Store already exists and then use it:

class Product < AR::Base
  belongs_to :order
  has_and_belongs_to_many :stores

  accepts_nested_attributes_for :stores, :reject_if => :check_store

  protected

    def check_store(store_attr)
      if _store = Store.find(store_attr['id'])
        self.store = _store
        return true
      end
      return false
    end
end

I have this code working fine in a current project.

Please, let me know if you found a better solution.

嗳卜坏 2024-10-08 18:39:08

我遇到了同样的问题,并通过将 :id 添加到嵌套参数列表来解决它。

def family_params
  params.require(:family).permit(:user_id, :address, people_attributes: [:id, :relation, :first_name, :last_name)
end

I had the same problem and solved it by adding :id to the nested parameter list.

def family_params
  params.require(:family).permit(:user_id, :address, people_attributes: [:id, :relation, :first_name, :last_name)
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文