has_many 通过清除协会关于群众协会的元数据

发布于 2024-10-07 10:38:33 字数 619 浏览 5 评论 0原文

嘿, 我不是 Rails 菜鸟,但这让我很困惑。 与 Rails 中有许多通过关联。当我通过酒单协会(或通过)表将葡萄酒大量分配给酒吧时,类似这样。

class WineBarController

  def update

    @winebar = WineBar.find(params[:id])

    @winebar.wines = Wine.find(params[:wine_bar][:wine_ids].split(","))  // Mass assign wines.

    render (@winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure) 

  end

end

这将删除与该酒吧关联的每个酒单行。然后它会找到 wine_ids 中的所有葡萄酒,我们假设它是一个以逗号分隔的葡萄酒 ID 字符串。然后它会在酒单中插入一个新的关联。这会很昂贵,但如果被破坏的关联行没有元数据,例如各个酒吧每杯和每瓶的价格,那就没问题了。

有没有办法让它不破坏所有内容,只需对数组进行可枚举比较并插入删除任何更改。我觉得这是 Rails 所做的事情,但我只是错过了一些明显的东西。

谢谢。

Hey,
Not a Rails noob but this has stumped me.
With has many through associations in Rails. When I mass assign wines to a winebar through a winelist association (or through) table with something like this.

class WineBarController

  def update

    @winebar = WineBar.find(params[:id])

    @winebar.wines = Wine.find(params[:wine_bar][:wine_ids].split(","))  // Mass assign wines.

    render (@winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure) 

  end

end

This will delete every winelist row associated with that winebar. Then it finds all of the wines in wine_ids, which we presume is a comma separated string of wine ids. Then it inserts back into the winelist a new association. This would be expensive, but fine if the destroyed association rows didn't have metadata such as the individual wine bar's price per glass and bottle.

Is there a way to have it not blow everything away, just do an enumerable comparison of the arrays and insert delete whatever changes. I feel like that's something rails does and I'm just missing something obvious.

Thanks.

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

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

发布评论

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

评论(1

⒈起吃苦の倖褔 2024-10-14 10:38:33

您的问题看起来像是更新方法中的第一个语句 - 您正在创建一个新的酒吧记录,而不是加载现有记录并更新它。这就是为什么当你检查记录时,没有任何迹象表明这种关系。 Rails 足够聪明,不会删除/创建列表中的每条记录,因此不必担心这一点。

如果您的表单使用标准 Rails 设置:

<% form_for @wine_bar do |f| %>

那么您可以像这样调用更新:

class WineBarController
  def update
    @winebar = WineBar.find(params[:id])
    render (@winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure) 
  end
end

您不需要使用 params[:wine_bar][:wine_ids] 显式更新您的记录,因为当您使用 params[:wine_bar] 更新它时,wine_ids 已包含在其中。我希望这有帮助!

更新:您提到,由于表单的设置方式,这不起作用,但您可以轻松修复它。在表单中,您需要将输入字段从 wine_bar[wine_ids] 重命名为 wine_bar[wine_ids_string]。然后,您只需要在模型中创建访问器,如下所示:

class WineBar < ActiveRecord::Base
  def wine_ids_string
    wines.map(&:id).join(',')
  end

  def wine_ids_string= id_string
    self.wine_ids = id_string.split(/,/)
  end
end

上面的第一个方法是“getter” - 它获取关联的 wine id 列表并将它们转换为表单可以使用的字符串。下一个方法是“setter”,它接受以逗号分隔的 ids 字符串,并将其分解为 wine_ids= 接受的数组。

您可能也对我的文章动态表单感兴趣Rails 中的元素,概述了 Rails 表单输入如何不限于数据库记录中的属性。可以使用任何一对访问器方法。

Your problem looks like it's with your first statement in the update method - you're creating a new wine bar record, instead of loading an existing record and updating it. That's why when you examine the record, there's nothing showing of the relationship. Rails is smart enough not to drop/create every record on the list, so don't worry about that.

If you're using the standard rails setup for your forms:

<% form_for @wine_bar do |f| %>

Then you can call your update like this:

class WineBarController
  def update
    @winebar = WineBar.find(params[:id])
    render (@winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure) 
  end
end

You don't need to explicitly update your record with params[:wine_bar][:wine_ids], because when you updated it with params[:wine_bar], the wine_ids were included as part of that. I hope this helps!

UPDATE: You mentioned that this doesn't work because of how the forms are setup, but you can fix it easily. In your form, you'll want to rename the input field from wine_bar[wine_ids] to wine_bar[wine_ids_string]. Then you just need to create the accessors in your model, like so:

class WineBar < ActiveRecord::Base
  def wine_ids_string
    wines.map(&:id).join(',')
  end

  def wine_ids_string= id_string
    self.wine_ids = id_string.split(/,/)
  end
end

The first method above is the "getter" - it takes the list of associated wine ids and converts them to a string that the form can use. The next method is the "setter", and it accepts a comma-delimited string of ids, and breaks it up into the array that wine_ids= accepts.

You might also be interested in my article Dynamic Form Elements in Rails, which outlines how rails form inputs aren't limited to the attributes in the database record. Any pair of accessor methods can be used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文