我有一系列地点
locations = ["california", "new york", "florida"]
我有一个名为foobar的模型has_many :places
。
Place
模型belongs_to :foobar
并且有一个相关列 - name:string
。
我有一个嵌套的表单,允许我选择适用于foobar的位置。 为了提供选项,我根据控制器中的位置列表构建了位置:
class FoobarController < ApplicationController
def edit
@foobar = Foobar.find(params[:id])
APP_CONFIG['locations'].each do |location|
@foobar.places.find_by_name(location) || @foobar.places.build(:name => location)
end
end
end
这几乎没有问题。我包含编辑方法的原因是因为这是有问题的。已填充的地点列表,但已存在的Foobar
地点显示在顶部。
示例时间! :) 的
我创建了一个新的Foobar
。在我的形式
我向下滚动到地方,我看到了
选项“加利福尼亚”,“纽约”
和“佛罗里达”。我检查“加州”
和“佛罗里达”并创建Foobar。
接下来我去编辑Foobar。再一次,我 向下滚动到我看到的地方 我检查了两个选项。那是 很棒,除了订单 选项出现的是 “加利福尼亚”,“佛罗里达”,“纽约” - 经过检查的地方位于顶部。
如何保留原始阵列中位置的顺序?
谢谢!
更新:视图代码:
<%= f.fields_for :places do |place| %>
<div class="place">
<%= place.hidden_field :name %>
<%= place.check_box :checked %>
<%= place.label :checked, place.object.name %>
</div>
<% end %>
答案 0 :(得分:1)
你不能......至少不是你这样做的方式。想想铁路的作用。它会自动按表的id(PK)列排序。由于您正在建造的记录不会有ID,因此每次都会将它们放在最后。你可能会使用CREATE和fudge id,但这很麻烦,可能会遇到严重的问题。
为了维持秩序(双关语),你需要某种数组指针系统:
class FoobarController < ApplicationController
def edit
@foobar = Foobar.find(params[:id])
@places = Array.new
APP_CONFIG['locations'].each do |location|
@places << @foobar.places.build(:name => location)
end
end
end
然后,在您的视图中,您需要遍历数组并手动 构建表单。我建议先查看源代码并查看嵌套表单的显示方式。
以下是我接近它的方法 - 每次构建(没有find_by_name)。然后,在您想要的模型中:
class Foo < ActiveRecord
has_many :places
accepts_nested_attributes_for :places, :reject_if => { |a| !APP_CONFIG['locations'].include?(a) || Place.find_by_name(a).nil? || !Place.find_by_name_and_foo_id(a, self.id).nil? }
end
现在,我还没有完全根据你的情况测试该代码,所以我会将其分解;
1。)拒绝提交的属性是否不在全局数组中(更多是安全问题)
2。)如果名称不是有效的地方(再次,安全),则拒绝
3。)拒绝该foo的地方是否存在ALREADY(您的班级为has_many:places)
答案 1 :(得分:0)
查看acts_as_list&gt;&gt; https://github.com/rails/acts_as_list,它明确地将项目的顺序存储在名为“position”的列中的has_many集合中。