如何保留 Rails3 中关联的顺序?

发布于 2024-10-09 01:13:39 字数 1337 浏览 3 评论 0原文

我有一个位置数组,

locations = ["california", "new york", "florida"]

我有一个名为 foobar 的模型,它 has_many :placesPlace 模型 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 地点出现在顶部。


示例时间! :)

  1. 我创建了一个新的 Foobar。以我的形式 我向下滚动到一些地方,然后我看到 选项“加利福尼亚”、“纽约” 和“佛罗里达”。我检查“加利福尼亚州” 和“florida”并创建 Foobar。

  2. 接下来我去编辑 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 %>

I have an array of locations

locations = ["california", "new york", "florida"]

I have a model called foobar that has_many :places.
the Place model belongs_to :foobar and has one relevant column - name:string.

I have a nested form that allows me to select locations applicable for the foobar.
To offer the options, I build the places based on my locations list in my controller:

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

This works almost without a problem. The reason I'm including the edit method is because that's the problematic one. The list of places DOES get populated, but the Foobar places that already existed appear on the top.


Example time! :)

  1. I create a new Foobar. In my form
    I scroll down to places and I see
    the options "california", "new york"
    and "florida". I check "california"
    and "florida" and create Foobar.

  2. Next I go to edit Foobar. Again, I
    scroll down to the places and I see
    that I checked two options. That's
    great, except that the order in
    which the options appear is
    "california", "florida", "new york" - checked places are on the top.

How can I preserve the order of the locations from my original array?

Thanks!


Update: the view code:

<%= 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 %>

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

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

发布评论

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

评论(2

泪意 2024-10-16 01:13:39

你不能……至少不能以你现在的方式去做。想想 Rails 的作用。它自动按表的 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.) 如果该位置已存在,则拒绝that foo (你的班级有_many :places)

You can't... At least not the way you are doing it. Think about what rails does. It automatically orders by the id (PK) column of a table. Since the records you are BUILDING wont have an id, they will be placed at the end - every time. You COULD finagle and use CREATE and fudge ids, but that's messy and could run into serious problems.

In order to maintain order (pun), you'll need some kind of array-pointer system:

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

Then, in your view you'll need to loop over the array and manually build the form. I recommend viewing the source and seeing how the nested form appears first.

Here's how I would approach it - build every time (no find_by_name). Then, in your model you want:

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

Now, I haven't actually tested that code exactly for your case, so I'll break it down;

1.) Reject if the submitted attribute isn't in the global array (more of a security concern)

2.) Reject if the name isn't a valid place (again, security)

3.) Reject if the place ALREADY exists for that foo (your class that has_many :places)

黑白记忆 2024-10-16 01:13:39

查看acts_as_list>> https://github.com/rails/acts_as_list,它明确地将项目的顺序存储在 has_many 集合中在名为“位置”的列中。

Check out acts_as_list >> https://github.com/rails/acts_as_list, It explicitly stores the order of items in a has_many collection in a column called "position".

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