Ruby Rails 4 个带 Active Record 的嵌套表单

Ruby on Rails 4 Nested Forms with Active Record

我是 Rails 的新手,刚刚构建我的第一个应用程序(来自 PHP 和 .NET 背景并且喜欢它顺便说一句)但是我 运行 遇到了一个问题我正在努力寻找答案,尽管我确信有一个简单的答案!

我的项目有3个主要模型;位置、服务和定位服务

有多种服务可用,一个位置可以有任意数量的服务。基本上我在位置服务中使用记录来存储所选服务的 ID 和位置的 ID。

我的模型简化版如下:

class Location < ActiveRecord::Base
    has_many :location_services
end

class Service < ActiveRecord::Base
    has_many :location_services
end

class LocationService < ActiveRecord::Base
    belongs_to :location
    belongs_to :service
end

我已经阅读了有关嵌套表单的内容,并使用 'accepts_nested_attributes_for' 允许子表单编辑从另一个模型中获取的数据,这听起来与我想要的非常相似,只是我不想只能够编辑我拥有的位置服务,我希望能够从每个可用服务中选择复选框,然后在选中并保存我的位置时,我希望它为位置服务中的每个选定服务创建一条记录 table 使用位置的 ID 和服务的 ID

我确定我可以使用 Services.all 轻松生成所有复选框,然后循环遍历它,然后在我的控制器中从 POST 中获取所有勾选的复选框,循环遍历它们并构建一个所有这些的数组,然后将该数组传递给 Location.location_services.create([]) 但这是 rails 我觉得可能有更好的方法吗?

所以首先,我是不是在用一种愚蠢的方式来做这件事?有没有更好的方法而不是 3 tables?是否有生成和保存所有服务的好方法?

非常感谢 大卫

has_many 关系为您的模型添加了许多方法。从中您只需要 collection_singular_ids 方法,它执行以下操作:

Replace the collection with the objects identified by the primary keys in ids. This method loads the models and calls collection=.

以上方法可与collection_check_boxes as explained in this tutorial结合使用。所以在你的情况下你会有这样的东西:

f.collection_check_boxes :location_service_ids, LocationService.all, :id, :name

请注意,最后一个参数(此处为 :name)是 text_method_option,它会为您的复选框生成标签。

最后但同样重要的是:不要忘记正确使用accepts_nested_attributes

非常感谢 Yan 在这方面的帮助,我终于设法解决了我的问题,而且事实证明它非常简单。我在这里发帖,希望对其他人有所帮助。

我需要做的是通过位置服务添加与服务的 has_many 关系,因此我的模型现在如下所示:

class Location < ActiveRecord::Base       
   has_many :services, :through => :location_services
   has_many :location_services

   accepts_nested_attributes_for :location_services
end

我更新了我的观点以包括:

<%= f.collection_check_boxes(:service_ids, Service.all, :id, :name) do |b| %>
    <%= b.label(class: "check_box") do %>
      <%= b.check_box %>
      <%= b.object.name %>
    <% end %>
<% end %>

然后在我的控制器中我有:

def location_params    
   params.require(:location).permit(:service_ids => [])
end

为简单起见,我删除了所有其他字段。然后最后在Update方法中,就这么简单:

def update
   @location.update(location_params)

   redirect_to @location, notice: 'Location was successfully updated.'
end

希望这对某人有所帮助!!

非常感谢 大卫